diff --git a/.gitea/workflows/docker-rh8-build-test.yml b/.gitea/workflows/docker-rh8-build-test.yml index ed569282d..3d070f71e 100644 --- a/.gitea/workflows/docker-rh8-build-test.yml +++ b/.gitea/workflows/docker-rh8-build-test.yml @@ -34,6 +34,7 @@ jobs: python3.12 -m pip install pytest python3.12 -m pip install colorama python3.12 -m pip install numpy + python3.12 -m pip install pyzmq - name: Python unit tests working-directory: ${{gitea.workspace}} diff --git a/.gitea/workflows/docker-rh9-build-test.yml b/.gitea/workflows/docker-rh9-build-test.yml index 9c2e392fd..2783d69ec 100644 --- a/.gitea/workflows/docker-rh9-build-test.yml +++ b/.gitea/workflows/docker-rh9-build-test.yml @@ -32,6 +32,7 @@ jobs: python3.12 -m pip install pytest python3.12 -m pip install colorama python3.12 -m pip install numpy + python3.12 -m pip install pyzmq - name: Python unit tests working-directory: ${{gitea.workspace}} diff --git a/.github/workflows/run_tests.yaml b/.github/workflows/run_tests.yaml index 7d3487f29..96d04205e 100644 --- a/.github/workflows/run_tests.yaml +++ b/.github/workflows/run_tests.yaml @@ -18,7 +18,7 @@ jobs: with: python-version: 3.12 cache: 'pip' - - run: pip install pytest numpy colorama + - run: pip install pytest numpy colorama pyzmq - uses: awalsh128/cache-apt-pkgs-action@latest with: diff --git a/pyctbgui/pyctbgui/services/Acquisition.py b/pyctbgui/pyctbgui/services/Acquisition.py index 58c972c51..b32b8a659 100644 --- a/pyctbgui/pyctbgui/services/Acquisition.py +++ b/pyctbgui/pyctbgui/services/Acquisition.py @@ -7,7 +7,7 @@ import zmq from PyQt5 import QtWidgets, uic import logging -from slsdet import readoutMode, runStatus, detectorType +from slsdet import readoutMode, runStatus, detectorType, Hz, MHz, kHz from pyctbgui.utils.defines import Defines from pyctbgui.utils.numpyWriter.npy_writer import NumpyFileManager from pyctbgui.utils.numpyWriter.npz_writer import NpzFileWriter @@ -58,12 +58,6 @@ class AcquisitionTab(QtWidgets.QWidget): self.view.spinBoxADCPipeline.setDisabled(True) self.view.spinBoxDBITPhase.setDisabled(True) self.view.spinBoxDBITPipeline.setDisabled(True) - self.view.labelRunF.setText("Run Clock Frequency (kHz):") - self.view.labelDBITF.setText("DBIT Clock Frequency (kHz):") - self.view.labelADCF.setText("ADC Clock Frequency (kHz):") - self.view.spinBoxRunF.setMaximum(250000) - self.view.spinBoxDBITF.setMaximum(250000) - self.view.spinBoxADCF.setMaximum(250000) def connect_ui(self): # For Acquistions Tab @@ -74,8 +68,11 @@ class AcquisitionTab(QtWidgets.QWidget): if self.det.type in [detectorType.CHIPTESTBOARD, detectorType.XILINX_CHIPTESTBOARD]: self.view.spinBoxRunF.editingFinished.connect(self.setRunFrequency) + self.view.comboBoxRunF.currentIndexChanged.connect(self.getRunFrequency) self.view.spinBoxADCF.editingFinished.connect(self.setADCFrequency) + self.view.comboBoxADCF.currentIndexChanged.connect(self.getADCFrequency) self.view.spinBoxDBITF.editingFinished.connect(self.setDBITFrequency) + self.view.comboBoxDBITF.currentIndexChanged.connect(self.getDBITFrequency) if self.det.type == detectorType.CHIPTESTBOARD: self.view.spinBoxADCPhase.editingFinished.connect(self.setADCPhase) self.view.spinBoxADCPipeline.editingFinished.connect(self.setADCPipeline) @@ -195,20 +192,43 @@ class AcquisitionTab(QtWidgets.QWidget): self.view.comboBoxROMode.currentIndexChanged.connect(self.setReadOut) self.getReadout() + + def _getFrequency(self, det_attr, spinbox, spinSetter, combobox): + spinbox.editingFinished.disconnect() + f = getattr(self.det, det_attr).value + unit = combobox.currentIndex() + + if unit == 2: #Hz + spinbox.setValue(f) + elif unit == 1: #kHz + spinbox.setValue(f / 1e3) + else: + spinbox.setValue(f / 1e6) + + spinbox.editingFinished.connect(spinSetter) + + def _setFrequency(self, det_attr, spinbox, combobox, title, getter): + value = spinbox.value() + idx = combobox.currentIndex() + + if idx == 0: + val = MHz(value) + elif idx == 1: + val = kHz(value) + else: + val = Hz((int)(value)) + + try: + setattr(self.det, det_attr, val) + except Exception as e: + QtWidgets.QMessageBox.warning(self.mainWindow, title + " Fail", str(e), QtWidgets.QMessageBox.Ok) + getter() + def getRunFrequency(self): - self.view.spinBoxRunF.editingFinished.disconnect() - self.view.spinBoxRunF.setValue(self.det.runclk) - self.view.spinBoxRunF.editingFinished.connect(self.setRunFrequency) + self._getFrequency('runclk', self.view.spinBoxRunF, self.setRunFrequency, self.view.comboBoxRunF) def setRunFrequency(self): - self.view.spinBoxRunF.editingFinished.disconnect() - try: - self.det.runclk = self.view.spinBoxRunF.value() - except Exception as e: - QtWidgets.QMessageBox.warning(self.mainWindow, "Run Frequency Fail", str(e), QtWidgets.QMessageBox.Ok) - # TODO: handling double event exceptions - self.view.spinBoxRunF.editingFinished.connect(self.setRunFrequency) - self.getRunFrequency() + self._setFrequency('runclk', self.view.spinBoxRunF, self.view.comboBoxRunF, "Run Frequency Fail", self.getRunFrequency) def getTransceiver(self): self.view.spinBoxTransceiver.editingFinished.disconnect() @@ -260,19 +280,10 @@ class AcquisitionTab(QtWidgets.QWidget): self.getDigital() def getADCFrequency(self): - self.view.spinBoxADCF.editingFinished.disconnect() - self.view.spinBoxADCF.setValue(self.det.adcclk) - self.view.spinBoxADCF.editingFinished.connect(self.setADCFrequency) + self._getFrequency('adcclk', self.view.spinBoxADCF, self.setADCFrequency, self.view.comboBoxADCF) def setADCFrequency(self): - self.view.spinBoxADCF.editingFinished.disconnect() - try: - self.det.adcclk = self.view.spinBoxADCF.value() - except Exception as e: - QtWidgets.QMessageBox.warning(self.mainWindow, "ADC Frequency Fail", str(e), QtWidgets.QMessageBox.Ok) - # TODO: handling double event exceptions - self.view.spinBoxADCF.editingFinished.connect(self.setADCFrequency) - self.getADCFrequency() + self._setFrequency('adcclk', self.view.spinBoxADCF, self.view.comboBoxADCF, "ADC Frequency Fail", self.getADCFrequency) def getADCPhase(self): self.view.spinBoxADCPhase.editingFinished.disconnect() @@ -305,19 +316,10 @@ class AcquisitionTab(QtWidgets.QWidget): self.getADCPipeline() def getDBITFrequency(self): - self.view.spinBoxDBITF.editingFinished.disconnect() - self.view.spinBoxDBITF.setValue(self.det.dbitclk) - self.view.spinBoxDBITF.editingFinished.connect(self.setDBITFrequency) + self._getFrequency('dbitclk', self.view.spinBoxDBITF, self.setDBITFrequency, self.view.comboBoxDBITF) def setDBITFrequency(self): - self.view.spinBoxDBITF.editingFinished.disconnect() - try: - self.det.dbitclk = self.view.spinBoxDBITF.value() - except Exception as e: - QtWidgets.QMessageBox.warning(self.mainWindow, "DBit Frequency Fail", str(e), QtWidgets.QMessageBox.Ok) - # TODO: handling double event exceptions - self.view.spinBoxDBITF.editingFinished.connect(self.setDBITFrequency) - self.getDBITFrequency() + self._setFrequency('dbitclk', self.view.spinBoxDBITF, self.view.comboBoxDBITF, "DBit Frequency Fail", self.getDBITFrequency) def getDBITPhase(self): self.view.spinBoxDBITPhase.editingFinished.disconnect() diff --git a/pyctbgui/pyctbgui/ui/acquisition.ui b/pyctbgui/pyctbgui/ui/acquisition.ui index c2d15dff6..ac36336ed 100644 --- a/pyctbgui/pyctbgui/ui/acquisition.ui +++ b/pyctbgui/pyctbgui/ui/acquisition.ui @@ -36,7 +36,7 @@ - + 0 @@ -45,13 +45,13 @@ - 125 + 120 31 - 125 + 120 31 @@ -61,18 +61,17 @@ QAbstractSpinBox::UpDownArrows + + 3 + - 1000 + 999999999.000000000000000 + + + 1.000000000000000 - 0 - - - - - - - Read Out Mode: + 0.000000000000000 @@ -117,13 +116,67 @@ + + + + Read Out Mode: + + + - Run Clock Frequency (MHz): + Run Clock Frequency: + + + + + 60 + 31 + + + + + 60 + 16777215 + + + + + MHz + + + + + kHz + + + + + Hz + + + + + + + + Qt::Horizontal + + + QSizePolicy::Expanding + + + + 10 + 20 + + + + @@ -152,13 +205,13 @@ - 125 + 185 32 - 125 + 185 32 @@ -210,6 +263,12 @@ 201 + + + 190 + 0 + + QFrame::StyledPanel @@ -217,16 +276,128 @@ QFrame::Sunken - - - + + + + ADC Pipeline: + + + + + + + Qt::Horizontal + + + QSizePolicy::Expanding + + - 200 - 0 + 10 + 20 + + + + - DBIT Clock Frequency (MHz): + DBIT Clock Phase (a.u.): + + + + + + + + 0 + 0 + + + + + 120 + 31 + + + + + 120 + 31 + + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + 3 + + + 999999999.000000000000000 + + + 1.000000000000000 + + + 0.000000000000000 + + + + + + + ADC Clock Phase (a.u.): + + + + + + + DBIT Pipeline: + + + + + + + Digital Samples: + + + + + + + + 0 + 0 + + + + + 120 + 31 + + + + + 120 + 31 + + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + 3 + + + 999999999.000000000000000 + + + 1.000000000000000 + + + 0.000000000000000 @@ -245,213 +416,7 @@ - ADC Clock Frequency (MHz): - - - - - - - - 0 - 0 - - - - - 125 - 31 - - - - - 125 - 31 - - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - 9999 - - - - - - - DBIT Pipeline: - - - - - - - - 0 - 0 - - - - - 125 - 31 - - - - - 125 - 31 - - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - 1000 - - - - - - - - 0 - 0 - - - - - 125 - 31 - - - - - 125 - 31 - - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - ADC Pipeline: - - - - - - - ADC Clock Phase (a.u.): - - - - - - - DBIT Clock Phase (a.u.): - - - - - - - Qt::Horizontal - - - QSizePolicy::Expanding - - - - 10 - 20 - - - - - - - - - 0 - 0 - - - - - 125 - 31 - - - - - 125 - 31 - - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - 1000 - - - - - - - - 0 - 0 - - - - - 125 - 31 - - - - - 125 - 31 - - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - - 0 - 0 - - - - - 125 - 31 - - - - - 125 - 31 - - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - 9999 + ADC Clock Frequency: @@ -462,7 +427,51 @@ - + + + + + 200 + 0 + + + + DBIT Clock Frequency: + + + + + + + + 60 + 31 + + + + + 60 + 16777215 + + + + + MHz + + + + + kHz + + + + + Hz + + + + + @@ -472,13 +481,13 @@ - 125 + 185 32 - 125 + 185 32 @@ -493,14 +502,60 @@ - - - - Digital Samples: + + + + + 0 + 0 + + + + + 185 + 31 + + + + + 185 + 31 + + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + 9999 - + + + + + 0 + 0 + + + + + 185 + 31 + + + + + 185 + 31 + + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + @@ -510,13 +565,13 @@ - 125 + 185 32 - 125 + 185 32 @@ -534,6 +589,90 @@ + + + + + 0 + 0 + + + + + 185 + 31 + + + + + 185 + 31 + + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + 9999 + + + + + + + + 0 + 0 + + + + + 185 + 31 + + + + + 185 + 31 + + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + 60 + 31 + + + + + 60 + 16777215 + + + + + MHz + + + + + kHz + + + + + Hz + + + + diff --git a/python/CMakeLists.txt b/python/CMakeLists.txt index 13e6abb3d..ffec1ac60 100755 --- a/python/CMakeLists.txt +++ b/python/CMakeLists.txt @@ -13,6 +13,7 @@ pybind11_add_module(_slsdet src/DurationWrapper.cpp src/pedestal.cpp src/bit.cpp + src/frequency.cpp ) target_link_libraries(_slsdet PUBLIC diff --git a/python/slsdet/__init__.py b/python/slsdet/__init__.py index 753267d81..f08e8acab 100755 --- a/python/slsdet/__init__.py +++ b/python/slsdet/__init__.py @@ -34,6 +34,9 @@ scanParameters = _slsdet.scanParameters currentSrcParameters = _slsdet.currentSrcParameters DurationWrapper = _slsdet.DurationWrapper pedestalParameters = _slsdet.pedestalParameters +Hz = _slsdet.Hz +kHz = _slsdet.kHz +MHz = _slsdet.MHz import os def read_version(): diff --git a/python/slsdet/detector.py b/python/slsdet/detector.py index eeed02b79..56e29800f 100755 --- a/python/slsdet/detector.py +++ b/python/slsdet/detector.py @@ -14,11 +14,12 @@ powerIndex = slsDetectorDefs.powerIndex detectorType = slsDetectorDefs.detectorType streamingInterface = slsDetectorDefs.streamingInterface + defs = slsDetectorDefs from .utils import element_if_equal, all_equal, get_set_bits, list_to_bitmask from .utils import Geometry, to_geo, element, reduce_time, is_iterable, hostname_list -from ._slsdet import xy, freeSharedMemory, getUserDetails +from ._slsdet import xy, Hz, freeSharedMemory, getUserDetails from .gaincaps import Mythen3GainCapsWrapper from . import utils as ut from .proxy import JsonProxy, ClkDivProxy, MaxPhaseProxy, ClkFreqProxy, PatLoopProxy, PatNLoopProxy, PatWaitProxy, PatWaitTimeProxy @@ -3441,15 +3442,21 @@ class Detector(CppDetectorApi): @element def runclk(self): """ - [Ctb] Sets Run clock frequency in MHz. \n - [Xilinx Ctb] Sets Run clock frequency in kHz. - """ + [Ctb][Xilinx Ctb] Sets Run clock frequency. + Example + -------- + >>> d.runclk + >>> 10MHz + >>> d.runclk = MHz(5) + >>> d.runclk = Hz(5 * 1000 * 1000) + >>> d.runclk = kHz(2000) + """ return self.getRUNClock() @runclk.setter def runclk(self, freq): - ut.set_using_dict(self.setRUNClock, freq) + ut.set_using_dict(self.setRUNClock, freq) @property @element @@ -3526,10 +3533,16 @@ class Detector(CppDetectorApi): @element def dbitclk(self): """ - [Ctb] Sets clock for latching the digital bits in MHz. \n - [Xilinx Ctb] clock for latching the digital bits in kHz. - """ + [Ctb][Xilinx Ctb] Sets clock for latching the digital bits. + Example + -------- + >>> d.dbitclk + >>> 10MHz + >>> d.dbitclk = MHz(5) + >>> d.dbitclk = Hz(5 * 1000 * 1000) + >>> d.dbitclk = kHz(2000) + """ return self.getDBITClock() @dbitclk.setter @@ -3657,10 +3670,16 @@ class Detector(CppDetectorApi): @element def adcclk(self): """ - [Ctb] Sets ADC clock frequency in MHz. \n - [Xilinx Ctb] Sets ADC clock frequency in kHz. - """ + [Ctb][Xilinx Ctb] Sets ADC clock frequency. + Example + -------- + >>> d.adcclk + >>> 10MHz + >>> d.adcclk = MHz(5) + >>> d.adcclk = Hz(5 * 1000 * 1000) + >>> d.adcclk = kHz(2000) + """ return self.getADCClock() @adcclk.setter @@ -3671,7 +3690,7 @@ class Detector(CppDetectorApi): @element def syncclk(self): """ - [Ctb] Sync clock in MHz. + [Ctb] Sync clock. :setter: Not implemented """ @@ -3704,7 +3723,7 @@ class Detector(CppDetectorApi): [Ctb][Mythen3][Xilinx Ctb] Gets the pattern file name including path of the last pattern uploaded. Returns an empty if nothing was uploaded or via a server default file """ - return self.getPatterFileName() + return self.getPatternFileName() def patternstart(self): """[Ctb][Mythen3][Xilinx Ctb] Starts pattern. """ diff --git a/python/src/detector.cpp b/python/src/detector.cpp index 3d2b3a049..ff14eaafa 100644 --- a/python/src/detector.cpp +++ b/python/src/detector.cpp @@ -1529,23 +1529,31 @@ void init_det(py::module &m) { Detector::setNumberOfAnalogSamples, py::arg(), py::arg() = Positions{}); CppDetectorApi.def("getADCClock", - (Result(Detector::*)(sls::Positions) const) & + (Result(Detector::*)(sls::Positions) const) & Detector::getADCClock, py::arg() = Positions{}); CppDetectorApi.def("setADCClock", - (void (Detector::*)(int, sls::Positions)) & + (void (Detector::*)(defs::Hz, sls::Positions)) & Detector::setADCClock, py::arg(), py::arg() = Positions{}); CppDetectorApi.def("getRUNClock", - (Result(Detector::*)(sls::Positions) const) & + (Result(Detector::*)(sls::Positions) const) & Detector::getRUNClock, py::arg() = Positions{}); CppDetectorApi.def("setRUNClock", - (void (Detector::*)(int, sls::Positions)) & + (void (Detector::*)(defs::Hz, sls::Positions)) & Detector::setRUNClock, py::arg(), py::arg() = Positions{}); + CppDetectorApi.def("getDBITClock", + (Result(Detector::*)(sls::Positions) const) & + Detector::getDBITClock, + py::arg() = Positions{}); + CppDetectorApi.def("setDBITClock", + (void (Detector::*)(defs::Hz, sls::Positions)) & + Detector::setDBITClock, + py::arg(), py::arg() = Positions{}); CppDetectorApi.def("getSYNCClock", - (Result(Detector::*)(sls::Positions) const) & + (Result(Detector::*)(sls::Positions) const) & Detector::getSYNCClock, py::arg() = Positions{}); CppDetectorApi.def("getPowerList", @@ -1646,14 +1654,6 @@ void init_det(py::module &m) { (void (Detector::*)(defs::readoutMode, sls::Positions)) & Detector::setReadoutMode, py::arg(), py::arg() = Positions{}); - CppDetectorApi.def("getDBITClock", - (Result(Detector::*)(sls::Positions) const) & - Detector::getDBITClock, - py::arg() = Positions{}); - CppDetectorApi.def("setDBITClock", - (void (Detector::*)(int, sls::Positions)) & - Detector::setDBITClock, - py::arg(), py::arg() = Positions{}); CppDetectorApi.def("getExternalSamplingSource", (Result(Detector::*)(sls::Positions) const) & Detector::getExternalSamplingSource, @@ -1891,9 +1891,9 @@ void init_det(py::module &m) { Detector::configureTransceiver, py::arg() = Positions{}); CppDetectorApi.def( - "getPatterFileName", + "getPatternFileName", (Result(Detector::*)(sls::Positions) const) & - Detector::getPatterFileName, + Detector::getPatternFileName, py::arg() = Positions{}); CppDetectorApi.def( "setPattern", diff --git a/python/src/frequency.cpp b/python/src/frequency.cpp new file mode 100644 index 000000000..ff08cf878 --- /dev/null +++ b/python/src/frequency.cpp @@ -0,0 +1,55 @@ +// SPDX-License-Identifier: LGPL-3.0-or-other +// Copyright (C) 2021 Contributors to the SLS Detector Package +/* +This file contains Python bindings for the Hz and for conversion to other units from and to string. +*/ +#include "py_headers.h" +#include + +#include "sls/ToString.h" +#include "sls/sls_detector_defs.h" + +namespace py = pybind11; + +constexpr double kHz = 1e3; +constexpr double MHz = 1e6; + +void init_freq(py::module &m) { + + py::class_ Hz(m, "Hz"); + Hz.def(py::init()); + Hz.def_readwrite("value", &slsDetectorDefs::Hz::value); + Hz.def("__repr__", [](const slsDetectorDefs::Hz &f) { + return sls::ToString(f); + }); + Hz.def("__str__", [](const slsDetectorDefs::Hz &f) { + return sls::ToString(f); + }); + + Hz.def(py::self == py::self); + Hz.def("__mul__", [](const slsDetectorDefs::Hz &h, int x) { + return slsDetectorDefs::Hz(h.value * x); + }, py::is_operator()); + Hz.def("__rmul__", [](const slsDetectorDefs::Hz &h, int x) { + return slsDetectorDefs::Hz(h.value * x); + }, py::is_operator()); + Hz.def("__truediv__", [](const slsDetectorDefs::Hz &h, int x) { + return slsDetectorDefs::Hz(h.value / x); + }, py::is_operator()); + Hz.def("__add__", [](const slsDetectorDefs::Hz &a, + const slsDetectorDefs::Hz &b) { + return slsDetectorDefs::Hz(a.value + b.value); + }, py::is_operator()); + Hz.def("__sub__", [](const slsDetectorDefs::Hz &a, + const slsDetectorDefs::Hz &b) { + return slsDetectorDefs::Hz(a.value - b.value); + }, py::is_operator()); + + m.def("kHz", [](double v) { + return slsDetectorDefs::Hz(static_cast(std::round(v * kHz))); + }); + + m.def("MHz", [](double v) { + return slsDetectorDefs::Hz(static_cast(std::round(v * MHz))); + }); +} \ No newline at end of file diff --git a/python/src/main.cpp b/python/src/main.cpp index 214f2b81c..6bc583cbd 100644 --- a/python/src/main.cpp +++ b/python/src/main.cpp @@ -21,6 +21,7 @@ void init_source(py::module &); void init_duration(py::module &); void init_pedestal(py::module &); void init_bit(py::module &); +void init_freq(py::module &); PYBIND11_MODULE(_slsdet, m) { m.doc() = R"pbdoc( @@ -42,6 +43,7 @@ PYBIND11_MODULE(_slsdet, m) { init_duration(m); init_pedestal(m); init_bit(m); + init_freq(m); // init_experimental(m); py::module io = m.def_submodule("io", "Submodule for io"); diff --git a/python/tests/test_det_api.py b/python/tests/test_det_api.py index e8d89560b..7bf942e22 100644 --- a/python/tests/test_det_api.py +++ b/python/tests/test_det_api.py @@ -396,6 +396,193 @@ def test_patternstart(session_simulator, request): Log(LogLevel.INFOGREEN, f"✅ {request.node.name} passed") + +@pytest.mark.detectorintegration +def test_runclk(session_simulator, request): + """ Test using runclk for ctb and xilinx_ctb.""" + det_type, num_interfaces, num_mods, d = session_simulator + assert d is not None + + from slsdet import Hz, MHz, kHz + + if det_type in ['ctb', 'xilinx_ctb']: + prev_runclk = d.getRUNClock() + + d.runclk + + # invalid value type + with pytest.raises(Exception) as exc_info: + d.runclk = 5e6 + + with pytest.raises(Exception) as exc_info: + d.runclk = 5 * 1000 * 1000 + + with pytest.raises(Exception) as exc_info: + d.runclk = Hz(5e6) + + d.runclk = MHz(15) + assert d.runclk.value == 15_000_000 + + d.runclk = MHz(14.5) + assert d.runclk.value == 14_500_000 + + d.runclk = kHz(15000.5) + assert d.runclk.value == 15_000_500 + + # invalid values from server + # max is 300MHz + with pytest.raises(Exception) as exc_info: + d.runclk = MHz(301) + + # min is 2MHz for ctb and 10MHz for xilinx_ctb + if det_type == 'ctb': + with pytest.raises(Exception) as exc_info: + d.runclk = MHz(1) + else: + with pytest.raises(Exception) as exc_info: + d.runclk = MHz(9) + + c = MHz(2) + for rc in [5, 10, 15, 20]: + d.runclk = rc * c + assert d.runclk.value == 40_000_000 + + for i in range(len(d)): + d.setRUNClock(prev_runclk[i], [i]) + + Log(LogLevel.INFOGREEN, f"✅ {request.node.name} passed") + + +@pytest.mark.detectorintegration +def test_adcclk(session_simulator, request): + """ Test using adcclk for ctb and xilinx_ctb.""" + det_type, num_interfaces, num_mods, d = session_simulator + assert d is not None + + from slsdet import Hz, MHz, kHz + + if det_type in ['ctb', 'xilinx_ctb']: + prev_adcclk = d.getADCClock() + + d.adcclk + + # invalid value type + with pytest.raises(Exception) as exc_info: + d.adcclk = 5e6 + + with pytest.raises(Exception) as exc_info: + d.adcclk = 5 * 1000 * 1000 + + with pytest.raises(Exception) as exc_info: + d.adcclk = Hz(5e6) + + d.adcclk = MHz(15) + assert d.adcclk.value == 15_000_000 + + d.adcclk = MHz(14.5) + assert d.adcclk.value == 14_500_000 + + d.adcclk = kHz(15000.5) + assert d.adcclk.value == 15_000_500 + + # invalid values from server + # max is 300MHz for xilinx and 54 MHz for ctb + if det_type == 'ctb': + with pytest.raises(Exception) as exc_info: + d.adcclk = MHz(66) + else: + with pytest.raises(Exception) as exc_info: + d.adcclk = MHz(301) + + # min is 2MHz for ctb and 10MHz for xilinx_ctb + if det_type == 'ctb': + with pytest.raises(Exception) as exc_info: + d.adcclk = MHz(1) + else: + with pytest.raises(Exception) as exc_info: + d.adcclk = MHz(9) + + c = MHz(2) + for rc in [5, 10, 15, 20]: + d.adcclk = rc * c + assert d.adcclk.value == 40_000_000 + + for i in range(len(d)): + d.setADCClock(prev_adcclk[i], [i]) + + Log(LogLevel.INFOGREEN, f"✅ {request.node.name} passed") + + +@pytest.mark.detectorintegration +def test_dbitclk(session_simulator, request): + """ Test using dbitclk for ctb and xilinx_ctb.""" + det_type, num_interfaces, num_mods, d = session_simulator + assert d is not None + + from slsdet import Hz, MHz, kHz + + if det_type in ['ctb', 'xilinx_ctb']: + prev_dbitclk = d.getDBITClock() + + d.dbitclk + + # invalid value type + with pytest.raises(Exception) as exc_info: + d.dbitclk = 5e6 + + with pytest.raises(Exception) as exc_info: + d.dbitclk = 5 * 1000 * 1000 + + with pytest.raises(Exception) as exc_info: + d.dbitclk = Hz(5e6) + + d.dbitclk = MHz(15) + assert d.dbitclk.value == 15_000_000 + + d.dbitclk = MHz(14.5) + assert d.dbitclk.value == 14_500_000 + + d.dbitclk = kHz(15000.5) + assert d.dbitclk.value == 15_000_500 + + # invalid values from server + # max is 300MHz + with pytest.raises(Exception) as exc_info: + d.dbitclk = MHz(301) + + # min is 2MHz for ctb and 10MHz for xilinx_ctb + if det_type == 'ctb': + with pytest.raises(Exception) as exc_info: + d.dbitclk = MHz(1) + else: + with pytest.raises(Exception) as exc_info: + d.dbitclk = MHz(9) + + c = MHz(2) + for rc in [5, 10, 15, 20]: + d.dbitclk = rc * c + assert d.dbitclk.value == 40_000_000 + + for i in range(len(d)): + d.setDBITClock(prev_dbitclk[i], [i]) + + Log(LogLevel.INFOGREEN, f"✅ {request.node.name} passed") + + + +@pytest.mark.detectorintegration +def test_syncclk(session_simulator, request): + """ Test using syncclk for ctb.""" + det_type, num_interfaces, num_mods, d = session_simulator + assert d is not None + + if det_type in ['ctb']: + d.syncclk + + Log(LogLevel.INFOGREEN, f"✅ {request.node.name} passed") + + + @pytest.mark.detectorintegration def test_v_limit(session_simulator, request): """Test v_limit.""" @@ -715,3 +902,4 @@ def test_dac(session_simulator, request): Log(LogLevel.INFOGREEN, f"✅ {request.node.name} passed") + diff --git a/python/tests/test_freq.py b/python/tests/test_freq.py new file mode 100644 index 000000000..c4e8b216e --- /dev/null +++ b/python/tests/test_freq.py @@ -0,0 +1,48 @@ +from slsdet import Hz, MHz, kHz + +def test_Hz(): + f = Hz(1) + assert f.value == 1 + f = Hz(1 * 1000) + assert f.value == 1000 + f = MHz(5) + assert f.value == 5_000_000 + f = MHz(0.5) + assert f.value == 500_000 + f = kHz(2.5) + assert f.value == 2500 + f = kHz(5000) + assert f.value == 5_000_000 + +def test_rounding_exact(): + f = MHz(1.234) + assert f.value == round(1_234_000) + + +def test_mul(): + c = MHz(1) + assert (c * 2).value == 2_000_000 + assert (c * 4).value == 4_000_000 + + +def test_rmul(): + c = MHz(1) + assert (2 * c).value == 2_000_000 + assert (4 * c).value == 4_000_000 + + c = c * 2 + assert c.value == 2_000_000 + + for rc in [1, 2, 4, 8]: + c = rc * c + assert c.value == 128_000_000 + + +def test_div(): + c = MHz(1) + assert (c / 2).value == 500_000 + +def test_eq(): + assert MHz(1) == MHz(1) + assert MHz(1) != MHz(2) + assert MHz(1) == kHz(1000) \ No newline at end of file diff --git a/slsDetectorServers/ctbDetectorServer/RegisterDefs.h b/slsDetectorServers/ctbDetectorServer/RegisterDefs.h index 02a35dd1e..333f367b6 100644 --- a/slsDetectorServers/ctbDetectorServer/RegisterDefs.h +++ b/slsDetectorServers/ctbDetectorServer/RegisterDefs.h @@ -628,11 +628,14 @@ #define ADC_SLOW_CTRL_DONE_OFST (1) #define ADC_SLOW_CTRL_DONE_MSK (0x00000001 << ADC_SLOW_CTRL_DONE_OFST) +/* Clock Measurement base reg */ +#define PLL_FREQ_MEASURE_REG (0x44 << MEM_MAP_SHIFT) + /* SPI */ #define SPI_CTRL_REG (0x48 << MEM_MAP_SHIFT) - #define SPI_CTRL_RX_EMPTY_BIT 2 - #define SPI_CTRL_CHIPSELECT_BIT 4 - #define SPI_CTRL_NBIT_OFST 16 +#define SPI_CTRL_RX_EMPTY_BIT 2 +#define SPI_CTRL_CHIPSELECT_BIT 4 +#define SPI_CTRL_NBIT_OFST 16 #define SPI_WRITEDATA_REG (0x49 << MEM_MAP_SHIFT) #define SPI_READDATA_REG (0x4A << MEM_MAP_SHIFT) diff --git a/slsDetectorServers/ctbDetectorServer/bin/ctbDetectorServer_developer b/slsDetectorServers/ctbDetectorServer/bin/ctbDetectorServer_developer index 0d314ffb4..b717a96dd 100755 Binary files a/slsDetectorServers/ctbDetectorServer/bin/ctbDetectorServer_developer and b/slsDetectorServers/ctbDetectorServer/bin/ctbDetectorServer_developer differ diff --git a/slsDetectorServers/ctbDetectorServer/slsDetectorFunctionList.c b/slsDetectorServers/ctbDetectorServer/slsDetectorFunctionList.c index 2cca46fb4..4f8ec83ae 100644 --- a/slsDetectorServers/ctbDetectorServer/slsDetectorFunctionList.c +++ b/slsDetectorServers/ctbDetectorServer/slsDetectorFunctionList.c @@ -13,6 +13,7 @@ #include "communication_funcs_UDP.h" #include "loadPattern.h" +#include #include #include #include @@ -65,7 +66,7 @@ uint8_t adcEnableMask_10g = 0xFF; uint32_t transceiverMask = DEFAULT_TRANSCEIVER_MASK; int32_t clkPhase[NUM_CLOCKS] = {}; -uint32_t clkFrequency[NUM_CLOCKS] = {40, 20, 20, 200}; +uint32_t clkFrequency[NUM_CLOCKS] = {}; int dacValues[NDAC_ONLY] = {}; int powerValues[NPWR] = {}; // powerIndex (A->IO, Chip) @@ -557,7 +558,7 @@ void setupDetector() { 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); + PLL_CNTRL_ADDR_OFST, PLL_FREQ_MEASURE_REG); ALTERA_PLL_ResetPLLAndReconfiguration(); resetCore(); @@ -632,10 +633,16 @@ void setupDetector() { DEFAULT_NUM_SAMPLES); // update databytes and allocate ram setNumTransceiverSamples(DEFAULT_NUM_SAMPLES); setNumFrames(DEFAULT_NUM_FRAMES); - setExpTime(DEFAULT_EXPTIME); + initError = setExpTime(DEFAULT_EXPTIME, initErrorMessage); + if (initError == FAIL) + return; setNumTriggers(DEFAULT_NUM_CYCLES); - setPeriod(DEFAULT_PERIOD); - setDelayAfterTrigger(DEFAULT_DELAY); + initError = setPeriod(DEFAULT_PERIOD, initErrorMessage); + if (initError == FAIL) + return; + initError = setDelayAfterTrigger(DEFAULT_DELAY, initErrorMessage); + if (initError == FAIL) + return; setTiming(DEFAULT_TIMING_MODE); setADCEnableMask(BIT32_MSK); setADCEnableMask_10G(BIT32_MSK); @@ -1134,64 +1141,132 @@ int setNumTransceiverSamples(int val) { int getNumTransceiverSamples() { return ntSamples; } -int setExpTime(int64_t val) { +int setExpTime(int64_t val, char *mess) { setPatternWaitInterval(0, val); - // validate for tolerance - int64_t retval = getExpTime(); + // validate + uint64_t arg_clocks = ns_to_clocks(val, clkFrequency[RUN_CLK]); + uint64_t retval_clocks = getPatternWaitClocks(0); + if (arg_clocks != retval_clocks) { + sprintf(mess, + "Failed to set exposure time. Could not set number of clocks " + "to %lld, read %lld\n", + (long long int)arg_clocks, (long long int)retval_clocks); + LOG(logERROR, (mess)); + return FAIL; + } + + // log rounding if any + int64_t retval = getPatternWaitInterval(0); if (val != retval) { + LOG(logWARNING, ("Rounding to %lld ns due to clock frequency\n", + (long long int)retval)); + } + + return OK; +} + +int getExpTime(int64_t *retval, char *mess) { + *retval = getPatternWaitInterval(0); + if (*retval == -1) { + sprintf(mess, "Failed to get exposure time.\n"); + LOG(logERROR, (mess)); return FAIL; } return OK; } -int64_t getExpTime() { return getPatternWaitInterval(0); } - -int setPeriod(int64_t val) { +int setPeriod(int64_t val, char *mess) { if (val < 0) { - LOG(logERROR, ("Invalid period: %lld ns\n", (long long int)val)); + sprintf(mess, "Invalid period: %lld ns\n", (long long int)val); + LOG(logERROR, (mess)); return FAIL; } 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); + uint64_t arg_clocks = ns_to_clocks(val, clkFrequency[SYNC_CLK]); + set64BitReg(arg_clocks, PERIOD_LSB_REG, PERIOD_MSB_REG); - // validate for tolerance - int64_t retval = getPeriod(); - val /= (1E-3 * clkFrequency[SYNC_CLK]); - if (val != retval) { + // validate + uint64_t retval_clocks = get64BitReg(PERIOD_LSB_REG, PERIOD_MSB_REG); + if (arg_clocks != retval_clocks) { + sprintf(mess, + "Failed to set period. Could not set number of clocks " + "to %lld, red %lld\n", + (long long int)arg_clocks, (long long int)retval_clocks); + LOG(logERROR, (mess)); return FAIL; } + + // log rounding if any + int64_t retval = 0; + if (getPeriod(&retval, mess) == FAIL) { + return FAIL; + } + if (val != retval) { + LOG(logWARNING, ("Rounding to %lld ns due to clock frequency\n", + (long long int)retval)); + } + return OK; } -int64_t getPeriod() { - return get64BitReg(PERIOD_LSB_REG, PERIOD_MSB_REG) / - (1E-3 * clkFrequency[SYNC_CLK]); +int getPeriod(int64_t *retval, char *mess) { + if (clkFrequency[SYNC_CLK] == 0) { + sprintf(mess, "Cannot get period. Sync clock frequency is 0.\n"); + LOG(logERROR, (mess)); + return FAIL; + } + uint64_t numClocks = get64BitReg(PERIOD_LSB_REG, PERIOD_MSB_REG); + *retval = clocks_to_ns(numClocks, clkFrequency[SYNC_CLK]); + return OK; } -int setDelayAfterTrigger(int64_t val) { +int setDelayAfterTrigger(int64_t val, char *mess) { if (val < 0) { - LOG(logERROR, - ("Invalid delay after trigger: %lld ns\n", (long long int)val)); + sprintf(mess, "Invalid delay after trigger: %lld ns\n", + (long long int)val); + LOG(logERROR, (mess)); return FAIL; } 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); + uint64_t arg_clocks = ns_to_clocks(val, clkFrequency[SYNC_CLK]); + set64BitReg(arg_clocks, DELAY_LSB_REG, DELAY_MSB_REG); - // validate for tolerance - int64_t retval = getDelayAfterTrigger(); - val /= (1E-3 * clkFrequency[SYNC_CLK]); - if (val != retval) { + // validate + uint64_t retval_clocks = get64BitReg(DELAY_LSB_REG, DELAY_MSB_REG); + if (arg_clocks != retval_clocks) { + sprintf( + mess, + "Failed to set delay after trigger. Could not set number of clocks " + "to %lld, read %lld\n", + (long long int)arg_clocks, (long long int)retval_clocks); + LOG(logERROR, (mess)); return FAIL; } + + // log rounding if any + int64_t retval = 0; + if (getDelayAfterTrigger(&retval, mess) == FAIL) { + return FAIL; + } + if (val != retval) { + LOG(logWARNING, ("Rounding to %lld ns due to clock frequency\n", + (long long int)retval)); + } + return OK; } -int64_t getDelayAfterTrigger() { - return get64BitReg(DELAY_LSB_REG, DELAY_MSB_REG) / - (1E-3 * clkFrequency[SYNC_CLK]); +int getDelayAfterTrigger(int64_t *retval, char *mess) { + if (clkFrequency[SYNC_CLK] == 0) { + sprintf(mess, + "Cannot get delay after trigger. Sync clock frequency is 0.\n"); + LOG(logERROR, (mess)); + return FAIL; + } + uint64_t numClocks = get64BitReg(DELAY_LSB_REG, DELAY_MSB_REG); + *retval = clocks_to_ns(numClocks, clkFrequency[SYNC_CLK]); + return OK; } int64_t getNumFramesLeft() { @@ -1202,14 +1277,27 @@ 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]); +int getDelayAfterTriggerLeft(int64_t *retval, char *mess) { + if (clkFrequency[SYNC_CLK] == 0) { + sprintf(mess, "Cannot get delay after trigger left. Sync clock " + "frequency is 0.\n"); + LOG(logERROR, (mess)); + return FAIL; + } + uint64_t numClocks = get64BitReg(DELAY_LEFT_LSB_REG, DELAY_LEFT_MSB_REG); + *retval = clocks_to_ns(numClocks, clkFrequency[SYNC_CLK]); + return OK; } -int64_t getPeriodLeft() { - return get64BitReg(PERIOD_LEFT_LSB_REG, PERIOD_LEFT_MSB_REG) / - (1E-3 * clkFrequency[SYNC_CLK]); +int getPeriodLeft(int64_t *retval, char *mess) { + if (clkFrequency[SYNC_CLK] == 0) { + sprintf(mess, "Cannot get period left. Sync clock frequency is 0.\n"); + LOG(logERROR, (mess)); + return FAIL; + } + uint64_t numClocks = get64BitReg(PERIOD_LEFT_LSB_REG, PERIOD_LEFT_MSB_REG); + *retval = clocks_to_ns(numClocks, clkFrequency[SYNC_CLK]); + return OK; } int64_t getFramesFromStart() { @@ -1218,13 +1306,14 @@ int64_t getFramesFromStart() { } int64_t getActualTime() { - return get64BitReg(TIME_FROM_START_LSB_REG, TIME_FROM_START_MSB_REG) / - (1E-3 * CLK_FREQ); + // reg in unit of 100ns + return get64BitReg(TIME_FROM_START_LSB_REG, TIME_FROM_START_MSB_REG) * 100; } int64_t getMeasurementTime() { - return get64BitReg(START_FRAME_TIME_LSB_REG, START_FRAME_TIME_MSB_REG) / - (1E-3 * CLK_FREQ); + // reg in unit of 100ns + return get64BitReg(START_FRAME_TIME_LSB_REG, START_FRAME_TIME_MSB_REG) * + 100; } /* parameters - settings */ @@ -2206,13 +2295,12 @@ int getMaxPhase(enum CLKINDEX ind) { LOG(logERROR, ("Unknown clock index %d to get max phase\n", ind)); return -1; } - int ret = ((double)PLL_VCO_FREQ_MHZ / (double)clkFrequency[ind]) * + int ret = ((double)PLL_VCO_FREQ_HZ / (double)clkFrequency[ind]) * MAX_PHASE_SHIFTS_STEPS; char *clock_names[] = {CLK_NAMES}; - LOG(logDEBUG1, - ("Max Phase Shift (%s): %d (Clock: %d MHz, VCO:%d MHz)\n", - clock_names[ind], ret, clkFrequency[ind], PLL_VCO_FREQ_MHZ)); + LOG(logDEBUG1, ("Max Phase Shift (%s): %d (Clock: %d Hz, VCO:%d Hz)\n", + clock_names[ind], ret, clkFrequency[ind], PLL_VCO_FREQ_HZ)); return ret; } @@ -2248,12 +2336,12 @@ int setFrequency(enum CLKINDEX ind, int val) { return FAIL; } char *clock_names[] = {CLK_NAMES}; - LOG(logINFO, ("\tSetting %s clock (%d) frequency to %d MHz\n", + LOG(logINFO, ("\tSetting %s clock (%d) frequency to %d Hz\n", clock_names[ind], ind, val)); // check adc clk too high if (ind == ADC_CLK && val > MAXIMUM_ADC_CLK) { - LOG(logERROR, ("Frequency %d MHz too high for ADC\n", val)); + LOG(logERROR, ("Frequency %d Hz too high for ADC\n", val)); return FAIL; } @@ -2265,8 +2353,8 @@ int setFrequency(enum CLKINDEX ind, int val) { // Calculate and set output frequency clkFrequency[ind] = - ALTERA_PLL_SetOuputFrequency(ind, PLL_VCO_FREQ_MHZ, val); - LOG(logINFO, ("\t%s clock (%d) frequency set to %d MHz\n", clock_names[ind], + ALTERA_PLL_SetOutputFrequency(ind, PLL_VCO_FREQ_HZ, val); + LOG(logINFO, ("\t%s clock (%d) frequency set to %d Hz\n", clock_names[ind], ind, clkFrequency[ind])); // phase reset by pll (when setting output frequency) @@ -2294,6 +2382,17 @@ int getFrequency(enum CLKINDEX ind) { LOG(logERROR, ("Unknown clock index %d to get frequency\n", ind)); return -1; } +#ifndef VIRTUAL + // get the measured frequency from the firmware + int measuredFreqHz = ALTERA_PLL_getFrequency(ind); + + // checking against 0 here ensures compatibility with old firmware, TODO: + // remove this check at some point + if (measuredFreqHz != 0) { + // Round to nearest Hz. (should we round at all ?) + clkFrequency[ind] = measuredFreqHz; + } +#endif return clkFrequency[ind]; } @@ -2507,10 +2606,21 @@ void *start_timer(void *arg) { return NULL; } - int64_t periodNs = getPeriod(); + int64_t periodNs = 0; + int64_t expUs = 0; + { + char mess[MAX_STR_LENGTH] = {0}; + if (getPeriod(&periodNs, mess) == FAIL) { + LOG(logERROR, ("Failed to get period.\n")); + return NULL; + } + if (getExpTime(&expUs, mess) == FAIL) { + LOG(logERROR, ("Failed to get exposure time.\n")); + return NULL; + } + expUs /= 1000; + } int numFrames = (getNumFrames() * getNumTriggers()); - int64_t expUs = getExpTime() / 1000; - int imageSize = dataBytes; int dataSize = UDP_PACKET_DATA_BYTES; int packetSize = sizeof(sls_detector_header) + dataSize; diff --git a/slsDetectorServers/ctbDetectorServer/slsDetectorFunctionList.h b/slsDetectorServers/ctbDetectorServer/slsDetectorFunctionList.h index 3dccdf8c1..e5db4281f 100644 --- a/slsDetectorServers/ctbDetectorServer/slsDetectorFunctionList.h +++ b/slsDetectorServers/ctbDetectorServer/slsDetectorFunctionList.h @@ -98,10 +98,10 @@ void setNumFrames(int64_t val); int64_t getNumFrames(); void setNumTriggers(int64_t val); int64_t getNumTriggers(); -int setExpTime(int64_t val); -int64_t getExpTime(); -int setPeriod(int64_t val); -int64_t getPeriod(); +int setExpTime(int64_t val, char *mess); +int getExpTime(int64_t *retval, char *mess); +int setPeriod(int64_t val, char *mess); +int getPeriod(int64_t *retval, char *mess); int setNumAnalogSamples(int val); int getNumAnalogSamples(); int setNumDigitalSamples(int val); @@ -111,10 +111,10 @@ int getNumTransceiverSamples(); int64_t getNumFramesLeft(); int64_t getNumTriggersLeft(); -int setDelayAfterTrigger(int64_t val); -int64_t getDelayAfterTrigger(); -int64_t getDelayAfterTriggerLeft(); -int64_t getPeriodLeft(); +int setDelayAfterTrigger(int64_t val, char *mess); +int getDelayAfterTrigger(int64_t *retval, char *mess); +int getDelayAfterTriggerLeft(int64_t *retval, char *mess); +int getPeriodLeft(int64_t *retval, char *mess); int64_t getFramesFromStart(); int64_t getActualTime(); int64_t getMeasurementTime(); diff --git a/slsDetectorServers/ctbDetectorServer/slsDetectorServer_defs.h b/slsDetectorServers/ctbDetectorServer/slsDetectorServer_defs.h index aeb66b82c..61b59b66a 100644 --- a/slsDetectorServers/ctbDetectorServer/slsDetectorServer_defs.h +++ b/slsDetectorServers/ctbDetectorServer/slsDetectorServer_defs.h @@ -44,13 +44,16 @@ #define DEFAULT_VLIMIT (0) #define DEFAULT_TIMING_MODE (AUTO_TIMING) #define DEFAULT_TX_UDP_PORT (0x7e9a) -#define DEFAULT_RUN_CLK (200) // 40 -#define DEFAULT_ADC_CLK (40) // 20 -#define DEFAULT_SYNC_CLK (40) // 20 -#define DEFAULT_DBIT_CLK (200) -#define NS_TO_CLK_CYCLE (1E-3) // ns to MHz +#define DEFAULT_RUN_CLK (80000000) // 80 MHz +#define DEFAULT_ADC_CLK (40000000) // 40 MHz +#define DEFAULT_SYNC_CLK (40000000) // 40 MHz +#define DEFAULT_DBIT_CLK (200000000) // 200 MHz +#define NS_TO_CLK_CYCLE (1E-9) // ns to MHz #define DEFAULT_TRANSCEIVER_MASK (0x3) +#define MIN_CLK_FREQ (2000000) // 2 MHz +#define MAX_CLK_FREQ (300000000) // 300 MHz + #define MAX_TRANSCEIVER_MASK (0xF) #define MAX_TRANSCEIVER_SAMPLES (0xFFFF) @@ -89,8 +92,8 @@ #define BIT32_MSK (0xFFFFFFFF) #define BIT16_MASK (0xFFFF) -#define MAXIMUM_ADC_CLK (65) -#define PLL_VCO_FREQ_MHZ (800) +#define MAXIMUM_ADC_CLK (65000000) // 65 MHz +#define PLL_VCO_FREQ_HZ (800000000) // 800MHz /* Struct Definitions */ typedef struct udp_header_struct { diff --git a/slsDetectorServers/gotthard2DetectorServer/slsDetectorFunctionList.h b/slsDetectorServers/gotthard2DetectorServer/slsDetectorFunctionList.h index 7c442f7b1..124a058f8 100644 --- a/slsDetectorServers/gotthard2DetectorServer/slsDetectorFunctionList.h +++ b/slsDetectorServers/gotthard2DetectorServer/slsDetectorFunctionList.h @@ -163,7 +163,6 @@ int setPhase(enum CLKINDEX ind, int val, int degrees); int getPhase(enum CLKINDEX ind, int degrees); int getMaxPhase(enum CLKINDEX ind); int validatePhaseinDegrees(enum CLKINDEX ind, int val, int retval); -// void setFrequency(enum CLKINDEX ind, int val); int getFrequency(enum CLKINDEX ind); int getVCOFrequency(enum CLKINDEX ind); int setReadoutSpeed(int val); diff --git a/slsDetectorServers/mythen3DetectorServer/bin/mythen3DetectorServer_developer b/slsDetectorServers/mythen3DetectorServer/bin/mythen3DetectorServer_developer index 490129740..28608b061 100755 Binary files a/slsDetectorServers/mythen3DetectorServer/bin/mythen3DetectorServer_developer and b/slsDetectorServers/mythen3DetectorServer/bin/mythen3DetectorServer_developer differ diff --git a/slsDetectorServers/mythen3DetectorServer/slsDetectorFunctionList.h b/slsDetectorServers/mythen3DetectorServer/slsDetectorFunctionList.h index 09f49d589..47bb0e1c4 100644 --- a/slsDetectorServers/mythen3DetectorServer/slsDetectorFunctionList.h +++ b/slsDetectorServers/mythen3DetectorServer/slsDetectorFunctionList.h @@ -195,7 +195,6 @@ int setPhase(enum CLKINDEX ind, int val, int degrees); int getPhase(enum CLKINDEX ind, int degrees); int getMaxPhase(enum CLKINDEX ind); int validatePhaseinDegrees(enum CLKINDEX ind, int val, int retval); -// void setFrequency(enum CLKINDEX ind, int val); int getFrequency(enum CLKINDEX ind); int getVCOFrequency(enum CLKINDEX ind); int getMaxClockDivider(); diff --git a/slsDetectorServers/slsDetectorServer/include/ALTERA_PLL.h b/slsDetectorServers/slsDetectorServer/include/ALTERA_PLL.h index d531db5b0..9c8b88677 100644 --- a/slsDetectorServers/slsDetectorServer/include/ALTERA_PLL.h +++ b/slsDetectorServers/slsDetectorServer/include/ALTERA_PLL.h @@ -20,6 +20,10 @@ void ALTERA_PLL_SetDefines(uint32_t creg, uint32_t preg, uint32_t rprmsk, uint32_t wpmsk, uint32_t prmsk, uint32_t amsk, int aofst, uint32_t wd2msk, int clk2Index); +#elif defined(CHIPTESTBOARDD) +void ALTERA_PLL_SetDefines(uint32_t creg, uint32_t preg, uint32_t rprmsk, + uint32_t wpmsk, uint32_t prmsk, uint32_t amsk, + int aofst, uint32_t freqreg); #else /** * Set Defines @@ -71,8 +75,15 @@ void ALTERA_PLL_SetModePolling(); /** * Calculate and write output frequency * @param clkIndex clock index - * @param pllVCOFreqMhz PLL VCO Frequency in Mhz + * @param pllVCOFreqHz PLL VCO Frequency in Hz * @param value frequency to set to * @param frequency set */ -int ALTERA_PLL_SetOuputFrequency(int clkIndex, int pllVCOFreqMhz, int value); +int ALTERA_PLL_SetOutputFrequency(int clkIndex, int pllVCOFreqHz, int value); + +/** + * get measured clock frequency + */ +#if defined(CHIPTESTBOARDD) +uint32_t ALTERA_PLL_getFrequency(uint32_t clkIDX); +#endif diff --git a/slsDetectorServers/slsDetectorServer/include/common.h b/slsDetectorServers/slsDetectorServer/include/common.h index 7c6139f16..6dbbaae4e 100644 --- a/slsDetectorServers/slsDetectorServer/include/common.h +++ b/slsDetectorServers/slsDetectorServer/include/common.h @@ -2,6 +2,7 @@ // Copyright (C) 2021 Contributors to the SLS Detector Package #pragma once +#include "clogger.h" #include "sls/md5.h" #include // int64_t #include @@ -21,6 +22,19 @@ enum numberMode { DEC, HEX }; enum PROGRAM_INDEX { PROGRAM_FPGA, PROGRAM_KERNEL, PROGRAM_SERVER }; +#define NS_PER_SEC 1000000000ULL +#define HALF_NS_PER_SEC (NS_PER_SEC / 2) +static inline uint64_t ns_to_clocks(uint64_t t, uint32_t freq_hz) { + return (t * (uint64_t)freq_hz + HALF_NS_PER_SEC) / NS_PER_SEC; +} +static inline uint64_t clocks_to_ns(uint64_t clocks, uint32_t freq_hz) { + if (freq_hz == 0) { + LOG(logERROR, ("Frequency is 0, cannot convert clocks to ns\n")); + return (uint64_t)-1; + } + return (clocks * (uint64_t)NS_PER_SEC + freq_hz / 2) / freq_hz; +} + /** * Convert a value from a range to a different range (eg voltage to dac or vice * versa) diff --git a/slsDetectorServers/slsDetectorServer/src/ALTERA_PLL.c b/slsDetectorServers/slsDetectorServer/src/ALTERA_PLL.c index 0bf12e61f..eed289ae5 100644 --- a/slsDetectorServers/slsDetectorServer/src/ALTERA_PLL.c +++ b/slsDetectorServers/slsDetectorServer/src/ALTERA_PLL.c @@ -130,7 +130,8 @@ uint32_t ALTERA_PLL_Cntrl_WrPrmtrMask = 0x0; #if defined(JUNGFRAUD) uint32_t ALTERA_PLL_Cntrl_DBIT_PLL_WrPrmtrMask = 0x0; int ALTERA_PLL_Cntrl_DBIT_ClkIndex = 0; - +#elif defined(CHIPTESTBOARDD) +uint32_t ALTERA_PLL_FREQ_MEASURE_BASE = 0x0; #endif uint32_t ALTERA_PLL_Cntrl_PLLRstMask = 0x0; uint32_t ALTERA_PLL_Cntrl_AddrMask = 0x0; @@ -150,6 +151,19 @@ void ALTERA_PLL_SetDefines(uint32_t creg, uint32_t preg, uint32_t rprmsk, ALTERA_PLL_Cntrl_DBIT_PLL_WrPrmtrMask = wd2msk; ALTERA_PLL_Cntrl_DBIT_ClkIndex = clk2Index; } +#elif defined(CHIPTESTBOARDD) +void ALTERA_PLL_SetDefines(uint32_t creg, uint32_t preg, uint32_t rprmsk, + uint32_t wpmsk, uint32_t prmsk, uint32_t amsk, + int aofst, uint32_t freqreg) { + ALTERA_PLL_Cntrl_Reg = creg; + ALTERA_PLL_Param_Reg = preg; + ALTERA_PLL_Cntrl_RcnfgPrmtrRstMask = rprmsk; + ALTERA_PLL_Cntrl_WrPrmtrMask = wpmsk; + ALTERA_PLL_Cntrl_PLLRstMask = prmsk; + ALTERA_PLL_Cntrl_AddrMask = amsk; + ALTERA_PLL_Cntrl_AddrOfst = aofst; + ALTERA_PLL_FREQ_MEASURE_BASE = freqreg; +} #else void ALTERA_PLL_SetDefines(uint32_t creg, uint32_t preg, uint32_t rprmsk, uint32_t wpmsk, uint32_t prmsk, uint32_t amsk, @@ -269,12 +283,12 @@ void ALTERA_PLL_SetModePolling() { ALTERA_PLL_MODE_PLLNG_MD_VAL, 0); } -int ALTERA_PLL_SetOuputFrequency(int clkIndex, int pllVCOFreqMhz, int value) { - LOG(logDEBUG1, ("C%d: Setting output frequency to %d (pllvcofreq: %dMhz)\n", - clkIndex, value, pllVCOFreqMhz)); +int ALTERA_PLL_SetOutputFrequency(int clkIndex, int pllVCOFreqHz, int value) { + LOG(logDEBUG1, ("C%d: Setting output frequency to %d (pllvcofreq: %dHz)\n", + clkIndex, value, pllVCOFreqHz)); - // calculate output frequency - uint32_t total_div = (float)pllVCOFreqMhz / (float)value; + // calculate output frequency, round to next closest integer division + uint32_t total_div = (pllVCOFreqHz + value / 2) / value; // assume 50% duty cycle uint32_t low_count = total_div / 2; @@ -307,11 +321,24 @@ int ALTERA_PLL_SetOuputFrequency(int clkIndex, int pllVCOFreqMhz, int value) { // as adc clock is stopped temporarily when resetting pll) ALTERA_PLL_ResetPLL(); - /*double temp = ((double)pllVCOFreqMhz / (double)(low_count + high_count)); + /*double temp = ((double)pllVCOFreqHz / (double)(low_count + high_count)); if ((temp - (int)temp) > 0.0001) { temp += 0.5; } return (int)temp; */ + +#if defined(CHIPTESTBOARDD) && !defined(VIRTUAL) + // wait for firmware to measure the actual frequency + usleep(2 * 1000 * 1000); + value = ALTERA_PLL_getFrequency(clkIndex); + LOG(logDEBUG1, ("Frequency is %d\n", value)); +#endif return value; } + +#if defined(CHIPTESTBOARDD) +uint32_t ALTERA_PLL_getFrequency(uint32_t clk_index) { + return bus_r(ALTERA_PLL_FREQ_MEASURE_BASE + clk_index * 2); +} +#endif \ No newline at end of file diff --git a/slsDetectorServers/slsDetectorServer/src/XILINX_PLL.c b/slsDetectorServers/slsDetectorServer/src/XILINX_PLL.c index 8adec26be..09f31df52 100644 --- a/slsDetectorServers/slsDetectorServer/src/XILINX_PLL.c +++ b/slsDetectorServers/slsDetectorServer/src/XILINX_PLL.c @@ -11,9 +11,9 @@ // leave some things away) // clang-format off -#define XILINX_PLL_INPUT_FREQ (100000) // 100 MHz -#define XILINX_PLL_MIN_FREQ (10000) -#define XILINX_PLL_MAX_FREQ (250000) +#define XILINX_PLL_INPUT_FREQ (100000000) // 100 MHz +#define XILINX_PLL_MIN_FREQ (10000000) +#define XILINX_PLL_MAX_FREQ (250000000) #define XILINX_PLL_MAX_CLK_DIV (256) #define XILINX_PLL_NUM_CLKS (7) #define XILINX_PLL_MAX_NUM_CLKS_FOR_GET (3) @@ -71,14 +71,14 @@ // clang-format on -// freq in kHz !! +// freq in Hz !! int XILINX_PLL_setFrequency(uint32_t clk_index, uint32_t freq) { if (clk_index >= XILINX_PLL_NUM_CLKS) { LOG(logERROR, ("XILINX_PLL: Invalid clock index %d\n", clk_index)); return 1; } if (freq < XILINX_PLL_MIN_FREQ || freq > XILINX_PLL_MAX_FREQ) { - LOG(logERROR, ("XILINX_PLL: Frequency %d kHz is out of range\n", freq)); + LOG(logERROR, ("XILINX_PLL: Frequency %d Hz is out of range\n", freq)); return 1; } @@ -160,11 +160,7 @@ uint32_t XILINX_PLL_getFrequency(uint32_t clk_index) { clk_index -= XILINX_PLL_MEASURE_BASE_ADDR0_MAX_CLKS; base_addr = XILINX_PLL_MEASURE_BASE_ADDR1; } - uint32_t addr = base_addr + clk_index * XILINX_PLL_MEASURE_WIDTH; - uint32_t counter_val = bus_r_csp2(addr); - // Hz => round to nearest kHz - uint32_t freq_kHz = (counter_val + 500) / 1000; // round to nearest kHz - return freq_kHz; + return bus_r_csp2(base_addr + clk_index * XILINX_PLL_MEASURE_WIDTH); } bool XILINX_PLL_isLocked() { diff --git a/slsDetectorServers/slsDetectorServer/src/loadPattern.c b/slsDetectorServers/slsDetectorServer/src/loadPattern.c index 929460897..154094b87 100644 --- a/slsDetectorServers/slsDetectorServer/src/loadPattern.c +++ b/slsDetectorServers/slsDetectorServer/src/loadPattern.c @@ -11,7 +11,7 @@ #ifdef MYTHEN3D extern enum TLogLevel trimmingPrint; -extern uint32_t clkDivider[]; +extern int getFrequency(enum CLKINDEX ind); #endif #if defined(CHIPTESTBOARDD) || defined(XILINX_CHIPTESTBOARDD) extern uint32_t clkFrequency[]; @@ -277,6 +277,14 @@ int validate_getPatternWaitClocksAndInterval(char *message, int level, *waittime = getPatternWaitClocks(level); } else { *waittime = getPatternWaitInterval(level); + if (*waittime == (uint64_t)-1) { + sprintf( + message, + "Cannot get pattern wait interval for level %d. runclk is 0.\n", + level); + LOG(logERROR, (message)); + return FAIL; + } } return OK; } @@ -297,17 +305,17 @@ uint64_t getPatternWaitClocks(int level) { uint64_t getPatternWaitInterval(int level) { uint64_t numClocks = getPatternWaitClocks(level); - int runclk = 0; + uint32_t runclk = 0; #if defined(CHIPTESTBOARDD) || defined(XILINX_CHIPTESTBOARDD) runclk = clkFrequency[RUN_CLK]; #elif MYTHEN3D - runclk = clkDivider[SYSTEM_C0]; + runclk = getFrequency(SYSTEM_C0); #endif if (runclk == 0) { LOG(logERROR, ("runclk is 0. Cannot divide by 0. Returning -1.\n")); return -1; } - return numClocks / (NS_TO_CLK_CYCLE * runclk); + return clocks_to_ns(numClocks, runclk); } int validate_setPatternWaitClocksAndInterval(char *message, int level, @@ -321,27 +329,50 @@ int validate_setPatternWaitClocksAndInterval(char *message, int level, return FAIL; } - uint64_t retval = 0; if (clocks) { setPatternWaitClocks(level, waittime); // validate result - retval = getPatternWaitClocks(level); + uint64_t retval = getPatternWaitClocks(level); LOG(logDEBUG1, ("Pattern wait time in clocks (level:%d) retval: %d\n", level, (long long int)retval)); - } else { - setPatternWaitInterval(level, waittime); - // validate result - retval = getPatternWaitInterval(level); - LOG(logDEBUG1, ("Pattern wait time (level:%d) retval: %d\n", level, - (long long int)retval)); + + int ret = OK; + char mode[128]; + memset(mode, 0, sizeof(mode)); + sprintf(mode, "set pattern Loop %d wait time (clocks)", level); + validate64(&ret, message, waittime, retval, mode, DEC); + return ret; } - int ret = OK; - char mode[128]; - memset(mode, 0, sizeof(mode)); - sprintf(mode, "set pattern Loop %d wait time", level); - validate64(&ret, message, waittime, retval, mode, DEC); - return ret; + // interval + setPatternWaitInterval(level, waittime); + + // validate + uint32_t runclk = 0; +#if defined(CHIPTESTBOARDD) || defined(XILINX_CHIPTESTBOARDD) + runclk = clkFrequency[RUN_CLK]; +#elif MYTHEN3D + runclk = getFrequency(SYSTEM_C0); +#endif + uint64_t arg_clocks = ns_to_clocks(waittime, runclk); + uint64_t retval_clocks = getPatternWaitClocks(level); + if (arg_clocks != retval_clocks) { + sprintf(message, + "Failed to set pattern loop %d wait interval. Could not set " + "number of clocks to %lld, read %lld\n", + level, (long long int)arg_clocks, (long long int)retval_clocks); + LOG(logERROR, (message)); + return FAIL; + } + + // log rounding if any + uint64_t retval = getPatternWaitInterval(level); + if (waittime != retval) { + LOG(logWARNING, ("Rounding to %lld ns due to clock frequency\n", + (long long int)retval)); + } + + return OK; } void setPatternWaitClocks(int level, uint64_t t) { @@ -375,13 +406,13 @@ void setPatternWaitInterval(int level, uint64_t t) { #endif ("Setting Pattern Wait Time (level:%d) :%lld ns\n", level, (long long int)t)); - int runclk = 0; + uint32_t runclk = 0; #if defined(CHIPTESTBOARDD) || defined(XILINX_CHIPTESTBOARDD) runclk = clkFrequency[RUN_CLK]; #elif MYTHEN3D - runclk = clkDivider[SYSTEM_C0]; + runclk = getFrequency(SYSTEM_C0); #endif - uint64_t numClocks = t * (NS_TO_CLK_CYCLE * runclk); + uint64_t numClocks = ns_to_clocks(t, runclk); setPatternWaitClocks(level, numClocks); } diff --git a/slsDetectorServers/slsDetectorServer/src/slsDetectorServer_funcs.c b/slsDetectorServers/slsDetectorServer/src/slsDetectorServer_funcs.c index 755f78104..f4d9d930f 100644 --- a/slsDetectorServers/slsDetectorServer/src/slsDetectorServer_funcs.c +++ b/slsDetectorServers/slsDetectorServer/src/slsDetectorServer_funcs.c @@ -2402,7 +2402,11 @@ int get_exptime(int file_des) { "for this detector\n"); LOG(logERROR, (mess)); } else { +#if defined(CHIPTESTBOARDD) || defined(XILINX_CHIPTESTBOARDD) + ret = getExpTime(&retval, mess); +#else retval = getExpTime(); +#endif LOG(logDEBUG1, ("retval exptime %lld ns\n", (long long int)retval)); } #endif @@ -2472,6 +2476,9 @@ int set_exptime(int file_des) { "for this detector\n"); LOG(logERROR, (mess)); } else { +#if defined(CHIPTESTBOARDD) || defined(XILINX_CHIPTESTBOARDD) + ret = setExpTime(val, mess); +#else ret = setExpTime(val); int64_t retval = getExpTime(); LOG(logDEBUG1, ("retval exptime %lld ns\n", (long long int)retval)); @@ -2482,6 +2489,7 @@ int set_exptime(int file_des) { (long long int)val, (long long int)retval); LOG(logERROR, (mess)); } +#endif } #endif } @@ -2494,7 +2502,11 @@ int get_period(int file_des) { int64_t retval = -1; // get only +#if defined(CHIPTESTBOARDD) || defined(XILINX_CHIPTESTBOARDD) + ret = getPeriod(&retval, mess); +#else retval = getPeriod(); +#endif LOG(logDEBUG1, ("retval period %lld ns\n", (long long int)retval)); return Server_SendResult(file_des, INT64, &retval, sizeof(retval)); } @@ -2510,6 +2522,9 @@ int set_period(int file_des) { // only set if (Server_VerifyLock() == OK) { +#if defined(CHIPTESTBOARDD) || defined(XILINX_CHIPTESTBOARDD) + ret = setPeriod(arg, mess); +#else ret = setPeriod(arg); int64_t retval = getPeriod(); LOG(logDEBUG1, ("retval period %lld ns\n", (long long int)retval)); @@ -2518,6 +2533,7 @@ int set_period(int file_des) { (long long int)arg, (long long int)retval); LOG(logERROR, (mess)); } +#endif } return Server_SendResult(file_des, INT64, NULL, 0); } @@ -2533,7 +2549,11 @@ int get_delay_after_trigger(int file_des) { functionNotImplemented(); #else // get only +#if defined(CHIPTESTBOARDD) || defined(XILINX_CHIPTESTBOARDD) + ret = getDelayAfterTrigger(&retval, mess); +#else retval = getDelayAfterTrigger(); +#endif LOG(logDEBUG1, ("retval delay after trigger %lld ns\n", (long long int)retval)); #endif @@ -2557,6 +2577,9 @@ int set_delay_after_trigger(int file_des) { #else // only set if (Server_VerifyLock() == OK) { +#if defined(CHIPTESTBOARDD) || defined(XILINX_CHIPTESTBOARDD) + ret = setDelayAfterTrigger(arg, mess); +#else ret = setDelayAfterTrigger(arg); int64_t retval = getDelayAfterTrigger(); LOG(logDEBUG1, @@ -2568,6 +2591,7 @@ int set_delay_after_trigger(int file_des) { (long long int)arg, (long long int)retval); LOG(logERROR, (mess)); } +#endif } #endif return Server_SendResult(file_des, INT64, NULL, 0); @@ -2802,7 +2826,11 @@ int get_period_left(int file_des) { functionNotImplemented(); #else // get only +#if defined(CHIPTESTBOARDD) || defined(XILINX_CHIPTESTBOARDD) + ret = getPeriodLeft(&retval, mess); +#else retval = getPeriodLeft(); +#endif LOG(logDEBUG1, ("retval period left %lld ns\n", (long long int)retval)); #endif return Server_SendResult(file_des, INT64, &retval, sizeof(retval)); @@ -2819,7 +2847,11 @@ int get_delay_after_trigger_left(int file_des) { functionNotImplemented(); #else // get only +#if defined(CHIPTESTBOARDD) || defined(XILINX_CHIPTESTBOARDD) + ret = getDelayAfterTriggerLeft(&retval, mess); +#else retval = getDelayAfterTriggerLeft(); +#endif LOG(logDEBUG1, ("retval delay after trigger left %lld ns\n", (long long int)retval)); #endif @@ -3306,10 +3338,6 @@ int set_pattern_wait_clocks(int file_des) { if (ret == OK) { ret = validate_getPatternWaitClocksAndInterval(mess, loopLevel, &retval, 1); - if ((int64_t)timeval != GET_FLAG) { - validate64(&ret, mess, (int64_t)timeval, retval, - "set pattern wait clocks", DEC); - } } } #endif @@ -5693,11 +5721,9 @@ int set_clock_frequency(int file_des) { case ADC_CLOCK: c = ADC_CLK; break; -#if defined(CHIPTESTBOARDD) || defined(XILINX_CHIPTESTBOARDD) case DBIT_CLOCK: c = DBIT_CLK; break; -#endif case RUN_CLOCK: c = RUN_CLK; break; @@ -5718,26 +5744,38 @@ int set_clock_frequency(int file_des) { (int)c); if (getFrequency(c) == val) { - LOG(logINFO, ("Same %s: %d %s\n", modeName, val, - myDetectorType == GOTTHARD2 ? "Hz" : "MHz")); - } else { + LOG(logINFO, ("Same %s: %d %s\n", modeName, val, "Hz")); + } else if (val < MIN_CLK_FREQ || val > MAX_CLK_FREQ) { + ret = FAIL; + sprintf(mess, + "Cannot set frequency to %f MHz. Frequency outside " + "limits (%f - %f MHz)\n", + val / 1e6, MIN_CLK_FREQ / 1e6, MAX_CLK_FREQ / 1e6); + LOG(logERROR, (mess)); + } +#ifdef CHIPTESTBOARDD + else if (ind == ADC_CLOCK && (val > MAXIMUM_ADC_CLK)) { + ret = FAIL; + sprintf(mess, + "Cannot set ADC clock frequency to %f MHz. Frequency " + "outside limits (<= %f MHz)\n", + val / 1e6, MAXIMUM_ADC_CLK / 1e6); + LOG(logERROR, (mess)); + } +#endif + else { int ret = setFrequency(c, val); if (ret == FAIL) { - sprintf(mess, "Could not set %s to %d %s\n", modeName, val, - myDetectorType == XILINX_CHIPTESTBOARD ? "kHz" - : "MHz"); + sprintf(mess, "Could not set %s to %f MHz\n", modeName, + val / 1e6); LOG(logERROR, (mess)); } else { int retval = getFrequency(c); LOG(logDEBUG1, - ("retval %s: %d %s\n", modeName, retval, - myDetectorType == XILINX_CHIPTESTBOARD ? "kHz" - : "MHz")); -#if !defined(XILINX_CHIPTESTBOARDD) - // XCTB will give the actual frequency, which is not + ("retval %s: %f MHz\n", modeName, retval / 1e6)); + // both CTB's will give the actual frequency, which is not // 100% identical to the set frequency validate(&ret, mess, val, retval, modeName, DEC); -#endif } } } @@ -5790,14 +5828,8 @@ int get_clock_frequency(int file_des) { if (ret == OK) { retval = getFrequency(c); char *clock_names[] = {CLK_NAMES}; - LOG(logDEBUG1, - ("retval %s clock (%d) frequency: %d %s\n", clock_names[c], (int)c, - retval, - myDetectorType == XILINX_CHIPTESTBOARD - ? "kHz" - : (myDetectorType == GOTTHARD2 || myDetectorType == MYTHEN3 - ? "Hz" - : "MHz"))); + LOG(logDEBUG1, ("retval %s clock (%d) frequency: %d %s\n", + clock_names[c], (int)c, retval, "Hz")); } #endif return Server_SendResult(file_des, INT32, &retval, sizeof(retval)); @@ -7029,6 +7061,11 @@ int get_receiver_parameters(int file_des) { // exptime #ifdef MYTHEN3D i64 = 0; +#elif defined(CHIPTESTBOARDD) || defined(XILINX_CHIPTESTBOARDD) + if (getExpTime(&i64, mess) == FAIL) { + sprintf(mess, "Could not get exposure time.\n"); + return sendError(file_des); + } #else i64 = getExpTime(); #endif @@ -7037,7 +7074,15 @@ int get_receiver_parameters(int file_des) { return printSocketReadError(); // period + i64 = 0; +#if defined(CHIPTESTBOARDD) || defined(XILINX_CHIPTESTBOARDD) + if (getPeriod(&i64, mess) == FAIL) { + sprintf(mess, "Could not get period.\n"); + return sendError(file_des); + } +#else i64 = getPeriod(); +#endif n += sendData(file_des, &i64, sizeof(i64), INT64); if (n < 0) return printSocketReadError(); @@ -10894,13 +10939,6 @@ int set_pattern_wait_interval(int file_des) { if (Server_VerifyLock() == OK) { ret = validate_setPatternWaitClocksAndInterval(mess, loopLevel, timeval, 0); - if (ret == OK) { - uint64_t retval = 0; - ret = validate_getPatternWaitClocksAndInterval(mess, loopLevel, - &retval, 0); - validate64(&ret, mess, (int64_t)timeval, retval, - "set pattern wait interval", DEC); - } } #endif diff --git a/slsDetectorServers/xilinx_ctbDetectorServer/bin/xilinx_ctbDetectorServer_developer b/slsDetectorServers/xilinx_ctbDetectorServer/bin/xilinx_ctbDetectorServer_developer index 28c2a4532..175991ee8 100755 Binary files a/slsDetectorServers/xilinx_ctbDetectorServer/bin/xilinx_ctbDetectorServer_developer and b/slsDetectorServers/xilinx_ctbDetectorServer/bin/xilinx_ctbDetectorServer_developer differ diff --git a/slsDetectorServers/xilinx_ctbDetectorServer/slsDetectorFunctionList.c b/slsDetectorServers/xilinx_ctbDetectorServer/slsDetectorFunctionList.c index 625dbabd0..6d4e13a1a 100644 --- a/slsDetectorServers/xilinx_ctbDetectorServer/slsDetectorFunctionList.c +++ b/slsDetectorServers/xilinx_ctbDetectorServer/slsDetectorFunctionList.c @@ -363,7 +363,7 @@ void initStopServer() { return; } #ifdef VIRTUAL - sharedMemory_setStop(0); + setupDetector(); #endif } initCheckDone = 1; @@ -389,9 +389,13 @@ void setupDetector() { vLimit = DEFAULT_VLIMIT; #ifdef VIRTUAL - sharedMemory_setStatus(IDLE); - setupUDPCommParameters(); - initializePatternWord(); + if (isControlServer) { + sharedMemory_setStatus(IDLE); + setupUDPCommParameters(); + initializePatternWord(); + } else { + sharedMemory_setStop(0); + } #endif // initialization only at start up (restart fpga) initError = waitTransceiverReset(initErrorMessage); @@ -444,9 +448,15 @@ void setupDetector() { setNumFrames(DEFAULT_NUM_FRAMES); setNumTriggers(DEFAULT_NUM_CYCLES); setTiming(DEFAULT_TIMING_MODE); - setExpTime(DEFAULT_EXPTIME); - setPeriod(DEFAULT_PERIOD); - setDelayAfterTrigger(DEFAULT_DELAY); + initError = setExpTime(DEFAULT_EXPTIME, initErrorMessage); + if (initError == FAIL) + return; + initError = setPeriod(DEFAULT_PERIOD, initErrorMessage); + if (initError == FAIL) + return; + initError = setDelayAfterTrigger(DEFAULT_DELAY, initErrorMessage); + if (initError == FAIL) + return; setNextFrameNumber(DEFAULT_STARTING_FRAME_NUMBER); } @@ -766,63 +776,132 @@ int getNumTransceiverSamples() { return ((bus_r(NO_SAMPLES_X_REG) & NO_SAMPLES_X_MSK) >> NO_SAMPLES_X_OFST); } -int setExpTime(int64_t val) { +int setExpTime(int64_t val, char *mess) { setPatternWaitInterval(0, val); - // validate for tolerance - int64_t retval = getExpTime(); + // validate + uint64_t arg_clocks = ns_to_clocks(val, clkFrequency[RUN_CLK]); + uint64_t retval_clocks = getPatternWaitClocks(0); + if (arg_clocks != retval_clocks) { + sprintf(mess, + "Failed to set exposure time. Could not set number of clocks " + "to %lld, read %lld\n", + (long long int)arg_clocks, (long long int)retval_clocks); + LOG(logERROR, (mess)); + return FAIL; + } + + // log rounding if any + int64_t retval = getPatternWaitInterval(0); if (val != retval) { + LOG(logWARNING, ("Rounding to %lld ns due to clock frequency\n", + (long long int)retval)); + } + + return OK; +} + +int getExpTime(int64_t *retval, char *mess) { + *retval = getPatternWaitInterval(0); + if (*retval == -1) { + sprintf(mess, "Failed to get exposure time.\n"); + LOG(logERROR, (mess)); return FAIL; } return OK; } -int64_t getExpTime() { return getPatternWaitInterval(0); } - -int setPeriod(int64_t val) { +int setPeriod(int64_t val, char *mess) { if (val < 0) { - LOG(logERROR, ("Invalid period: %lld ns\n", (long long int)val)); + sprintf(mess, "Invalid period: %lld ns\n", (long long int)val); + LOG(logERROR, (mess)); return FAIL; } LOG(logINFO, ("Setting period %lld ns\n", (long long int)val)); - val *= (NS_TO_CLK_CYCLE * clkFrequency[RUN_CLK]); - setU64BitReg(val, PERIOD_IN_REG_1, PERIOD_IN_REG_2); + uint64_t arg_clocks = ns_to_clocks(val, clkFrequency[RUN_CLK]); + setU64BitReg(arg_clocks, PERIOD_IN_REG_1, PERIOD_IN_REG_2); - // validate for tolerance - int64_t retval = getPeriod(); - val /= (NS_TO_CLK_CYCLE * clkFrequency[RUN_CLK]); - if (val != retval) { + // validate + uint64_t retval_clocks = getU64BitReg(PERIOD_IN_REG_1, PERIOD_IN_REG_2); + if (arg_clocks != retval_clocks) { + sprintf(mess, + "Failed to set period. Could not set number of clocks " + "to %lld, red %lld\n", + (long long int)arg_clocks, (long long int)retval_clocks); + LOG(logERROR, (mess)); return FAIL; } + + // log rounding if any + int64_t retval = 0; + if (getPeriod(&retval, mess) == FAIL) { + return FAIL; + } + if (val != retval) { + LOG(logWARNING, ("Rounding to %lld ns due to clock frequency\n", + (long long int)retval)); + } + return OK; } -int64_t getPeriod() { - return getU64BitReg(PERIOD_IN_REG_1, PERIOD_IN_REG_2) / - (NS_TO_CLK_CYCLE * clkFrequency[RUN_CLK]); +int getPeriod(int64_t *retval, char *mess) { + if (clkFrequency[RUN_CLK] == 0) { + sprintf(mess, "Cannot get period. Run clock frequency is 0.\n"); + LOG(logERROR, (mess)); + return FAIL; + } + uint64_t numClocks = getU64BitReg(PERIOD_IN_REG_1, PERIOD_IN_REG_2); + *retval = clocks_to_ns(numClocks, clkFrequency[RUN_CLK]); + return OK; } -int setDelayAfterTrigger(int64_t val) { +int setDelayAfterTrigger(int64_t val, char *mess) { if (val < 0) { - LOG(logERROR, ("Invalid delay after trigger: %ld ns\n", val)); + sprintf(mess, "Invalid delay after trigger: %lld ns\n", + (long long int)val); + LOG(logERROR, (mess)); return FAIL; } - LOG(logINFO, ("Setting delay after trigger %ld ns\n", val)); - val *= (NS_TO_CLK_CYCLE * clkFrequency[RUN_CLK]); - setU64BitReg(val, DELAY_IN_REG_1, DELAY_IN_REG_2); + LOG(logINFO, ("Setting delay after trigger %lld ns\n", (long long int)val)); + uint64_t arg_clocks = ns_to_clocks(val, clkFrequency[RUN_CLK]); + setU64BitReg(arg_clocks, DELAY_IN_REG_1, DELAY_IN_REG_2); - // validate for tolerance - int64_t retval = getDelayAfterTrigger(); - val /= (NS_TO_CLK_CYCLE * clkFrequency[RUN_CLK]); - if (val != retval) { + // validate + uint64_t retval_clocks = getU64BitReg(DELAY_IN_REG_1, DELAY_IN_REG_2); + if (arg_clocks != retval_clocks) { + sprintf( + mess, + "Failed to set delay after trigger. Could not set number of clocks " + "to %lld, read %lld\n", + (long long int)arg_clocks, (long long int)retval_clocks); + LOG(logERROR, (mess)); return FAIL; } + + // log rounding if any + int64_t retval = 0; + if (getDelayAfterTrigger(&retval, mess) == FAIL) { + return FAIL; + } + if (val != retval) { + LOG(logWARNING, ("Rounding to %lld ns due to clock frequency\n", + (long long int)retval)); + } + return OK; } -int64_t getDelayAfterTrigger() { - return getU64BitReg(DELAY_IN_REG_1, DELAY_IN_REG_2) / - (NS_TO_CLK_CYCLE * clkFrequency[RUN_CLK]); +int getDelayAfterTrigger(int64_t *retval, char *mess) { + if (clkFrequency[RUN_CLK] == 0) { + sprintf(mess, + "Cannot get delay after trigger. Run clock frequency is 0.\n"); + LOG(logERROR, (mess)); + return FAIL; + } + uint64_t numClocks = getU64BitReg(DELAY_IN_REG_1, DELAY_IN_REG_2); + *retval = clocks_to_ns(numClocks, clkFrequency[RUN_CLK]); + return OK; } int64_t getNumFramesLeft() { @@ -833,14 +912,27 @@ int64_t getNumTriggersLeft() { return getU64BitReg(CYCLES_OUT_REG_1, CYCLES_OUT_REG_2); } -int64_t getDelayAfterTriggerLeft() { - return getU64BitReg(DELAY_OUT_REG_1, DELAY_OUT_REG_2) / - (NS_TO_CLK_CYCLE * clkFrequency[RUN_CLK]); +int getDelayAfterTriggerLeft(int64_t *retval, char *mess) { + if (clkFrequency[RUN_CLK] == 0) { + sprintf(mess, "Cannot get delay after trigger left. Run clock " + "frequency is 0.\n"); + LOG(logERROR, (mess)); + return FAIL; + } + uint64_t numClocks = getU64BitReg(DELAY_OUT_REG_1, DELAY_OUT_REG_2); + *retval = clocks_to_ns(numClocks, clkFrequency[RUN_CLK]); + return OK; } -int64_t getPeriodLeft() { - return getU64BitReg(PERIOD_OUT_REG_1, PERIOD_OUT_REG_2) / - (NS_TO_CLK_CYCLE * clkFrequency[RUN_CLK]); +int getPeriodLeft(int64_t *retval, char *mess) { + if (clkFrequency[RUN_CLK] == 0) { + sprintf(mess, "Cannot get period left. Run clock frequency is 0.\n"); + LOG(logERROR, (mess)); + return FAIL; + } + uint64_t numClocks = getU64BitReg(PERIOD_OUT_REG_1, PERIOD_OUT_REG_2); + *retval = clocks_to_ns(numClocks, clkFrequency[RUN_CLK]); + return OK; } int64_t getFramesFromStart() { @@ -849,13 +941,14 @@ int64_t getFramesFromStart() { } int64_t getActualTime() { - return getU64BitReg(TIME_FROM_START_OUT_REG_1, TIME_FROM_START_OUT_REG_2) / - (NS_TO_CLK_CYCLE * clkFrequency[SYNC_CLK]); + // in unit of 100ns + return getU64BitReg(TIME_FROM_START_OUT_REG_1, TIME_FROM_START_OUT_REG_2) * + 100; } int64_t getMeasurementTime() { - return getU64BitReg(FRAME_TIME_OUT_REG_1, FRAME_TIME_OUT_REG_2) / - (NS_TO_CLK_CYCLE * clkFrequency[SYNC_CLK]); + // in unit of 100ns + return getU64BitReg(FRAME_TIME_OUT_REG_1, FRAME_TIME_OUT_REG_2) * 100; } /* parameters - dac, adc, hv */ @@ -1447,11 +1540,22 @@ void *start_timer(void *arg) { if (!isControlServer) { return NULL; } + int64_t periodNs = 0; + int64_t expUs = 0; + { + char mess[MAX_STR_LENGTH] = {0}; + if (getPeriod(&periodNs, mess) == FAIL) { + LOG(logERROR, ("Failed to get period.\n")); + return NULL; + } + if (getExpTime(&expUs, mess) == FAIL) { + LOG(logERROR, ("Failed to get exposure time.\n")); + return NULL; + } + expUs /= 1000; + } - int64_t periodNs = getPeriod(); int numFrames = (getNumFrames() * getNumTriggers()); - int64_t expUs = getExpTime() / 1000; - int imageSize = calculateDataBytes(); int maxDataSize = MAX_DATA_SIZE_IN_PACKET; int packetSize = sizeof(sls_detector_header) + maxDataSize; @@ -1716,11 +1820,11 @@ int setFrequency(enum CLKINDEX ind, int val) { } char *clock_names[] = {CLK_NAMES}; - LOG(logINFO, ("\tSetting %s clock (%d) frequency to %d kHz\n", + LOG(logINFO, ("\tSetting %s clock (%d) frequency to %d Hz\n", clock_names[ind], ind, val)); if (XILINX_PLL_setFrequency(ind, val) == FAIL) { - LOG(logERROR, ("\tCould not set %s clock (%d) frequency to %d kHz\n", + LOG(logERROR, ("\tCould not set %s clock (%d) frequency to %d Hz\n", clock_names[ind], ind, val)); return FAIL; } diff --git a/slsDetectorServers/xilinx_ctbDetectorServer/slsDetectorFunctionList.h b/slsDetectorServers/xilinx_ctbDetectorServer/slsDetectorFunctionList.h index 4d1ce9889..14de21741 100644 --- a/slsDetectorServers/xilinx_ctbDetectorServer/slsDetectorFunctionList.h +++ b/slsDetectorServers/xilinx_ctbDetectorServer/slsDetectorFunctionList.h @@ -84,10 +84,10 @@ void setNumFrames(int64_t val); int64_t getNumFrames(); void setNumTriggers(int64_t val); int64_t getNumTriggers(); -int setExpTime(int64_t val); -int64_t getExpTime(); -int setPeriod(int64_t val); -int64_t getPeriod(); +int setExpTime(int64_t val, char *mess); +int getExpTime(int64_t *retval, char *mess); +int setPeriod(int64_t val, char *mess); +int getPeriod(int64_t *retval, char *mess); int setNumAnalogSamples(int val); int getNumAnalogSamples(); int setNumDigitalSamples(int val); @@ -97,10 +97,10 @@ int getNumTransceiverSamples(); int64_t getNumFramesLeft(); int64_t getNumTriggersLeft(); -int setDelayAfterTrigger(int64_t val); -int64_t getDelayAfterTrigger(); -int64_t getDelayAfterTriggerLeft(); -int64_t getPeriodLeft(); +int setDelayAfterTrigger(int64_t val, char *mess); +int getDelayAfterTrigger(int64_t *retval, char *mess); +int getDelayAfterTriggerLeft(int64_t *retval, char *mess); +int getPeriodLeft(int64_t *retval, char *mess); int64_t getFramesFromStart(); int64_t getActualTime(); int64_t getMeasurementTime(); diff --git a/slsDetectorServers/xilinx_ctbDetectorServer/slsDetectorServer_defs.h b/slsDetectorServers/xilinx_ctbDetectorServer/slsDetectorServer_defs.h index 757df2e0c..adf4691bc 100644 --- a/slsDetectorServers/xilinx_ctbDetectorServer/slsDetectorServer_defs.h +++ b/slsDetectorServers/xilinx_ctbDetectorServer/slsDetectorServer_defs.h @@ -158,8 +158,11 @@ typedef struct udp_header_struct { enum CLKINDEX { RUN_CLK, ADC_CLK, SYNC_CLK, DBIT_CLK, NUM_CLOCKS }; #define CLK_NAMES "run", "adc", "sync", "dbit" -#define DEFAULT_RUN_CLK (20000) // 20 MHz -#define DEFAULT_ADC_CLK (100000) // 100 MHz -#define DEFAULT_SYNC_CLK (20000) // 20 MHz -#define DEFAULT_DBIT_CLK (100000) // 100 MHz -#define NS_TO_CLK_CYCLE (1E-6) // ns to kHz +#define DEFAULT_RUN_CLK (20000000) // 20 MHz +#define DEFAULT_ADC_CLK (100000000) // 100 MHz +#define DEFAULT_SYNC_CLK (20000000) // 20 MHz +#define DEFAULT_DBIT_CLK (100000000) // 100 MHz +#define NS_TO_CLK_CYCLE (1E-9) // ns to Hz + +#define MIN_CLK_FREQ (10000000) // 10 MHz +#define MAX_CLK_FREQ (300000000) // 300 MHz diff --git a/slsDetectorSoftware/generator/Caller.in.h b/slsDetectorSoftware/generator/Caller.in.h index f7128620e..e18dec02c 100644 --- a/slsDetectorSoftware/generator/Caller.in.h +++ b/slsDetectorSoftware/generator/Caller.in.h @@ -54,6 +54,9 @@ class Caller { return ToString(value, unit); } + std::string OutString(const Result &value, + const std::string &unit); + std::vector getAllCommands(); std::map GetDeprecatedCommands(); std::string list(int action); @@ -96,6 +99,7 @@ class Caller { defs::dacIndex parseDacIndex(int argIndex, bool isCtb); bool parseMV(int argIndex); defs::powerIndex parsePowerIndex(int argIndex); + defs::FrequencyUnit parseFrequencyUnit(const std::string &s); FunctionMap functions{ {"list", &Caller::list}, diff --git a/slsDetectorSoftware/generator/autocomplete/autocomplete.py b/slsDetectorSoftware/generator/autocomplete/autocomplete.py index 356e82eab..f236bcc67 100644 --- a/slsDetectorSoftware/generator/autocomplete/autocomplete.py +++ b/slsDetectorSoftware/generator/autocomplete/autocomplete.py @@ -16,6 +16,7 @@ type_values = { 'special::mv': ["mv", "mV"], "special::deg": ["deg"], "special::time_unit": ["s", "ms", "us", "ns"], + "special::freq_unit": ["Hz", "kHz", "MHz"], "special::hard": ["hard"], "special::force-delete-normal-file": ["--force-delete-normal-file"], "special::currentSourceFix": ["fix", "nofix"], @@ -40,11 +41,11 @@ def get_types(arg_types): #list of options with a command line call that fetches them #TODO! Rename sls_detector_get if "defs::dacIndex" in arg_types: - return "`sls_detector_get daclist | sed -e 's/.*\[\(.*\)\].*/\\1/' | sed 's/,//g'`" + return r"`sls_detector_get daclist | sed -e 's/.*\[\(.*\)\].*/\\1/' | sed 's/,//g'`" elif "defs::detectorSettings" in arg_types: - return "`sls_detector_get settingslist | sed -e 's/.*\[\(.*\)\].*/\\1/' | sed 's/,//g'`" + return r"`sls_detector_get settingslist | sed -e 's/.*\[\(.*\)\].*/\\1/' | sed 's/,//g'`" elif "defs::timingMode" in arg_types: - return "`sls_detector_get timinglist | sed -e 's/.*\[\(.*\)\].*/\\1/' | sed 's/,//g'`" + return r"`sls_detector_get timinglist | sed -e 's/.*\[\(.*\)\].*/\\1/' | sed 's/,//g'`" return ret diff --git a/slsDetectorSoftware/generator/autocomplete/bash_autocomplete.sh b/slsDetectorSoftware/generator/autocomplete/bash_autocomplete.sh index ff46a218a..433bd33d4 100644 --- a/slsDetectorSoftware/generator/autocomplete/bash_autocomplete.sh +++ b/slsDetectorSoftware/generator/autocomplete/bash_autocomplete.sh @@ -96,10 +96,18 @@ return 0 } __adcclk() { FCN_RETURN="" +if [[ ${IS_GET} -eq 1 ]]; then +if [[ "${cword}" == "2" ]]; then +FCN_RETURN="Hz MHz kHz" +fi +fi if [[ ${IS_GET} -eq 0 ]]; then if [[ "${cword}" == "2" ]]; then FCN_RETURN="" fi +if [[ "${cword}" == "3" ]]; then +FCN_RETURN="Hz MHz kHz" +fi fi return 0 } @@ -565,12 +573,12 @@ __dacname() { FCN_RETURN="" if [[ ${IS_GET} -eq 1 ]]; then if [[ "${cword}" == "2" ]]; then -FCN_RETURN="`sls_detector_get daclist | sed -e 's/.*\[\(.*\)\].*/\1/' | sed 's/,//g'`" +FCN_RETURN="`sls_detector_get daclist | sed -e 's/.*\[\(.*\)\].*/\\1/' | sed 's/,//g'`" fi fi if [[ ${IS_GET} -eq 0 ]]; then if [[ "${cword}" == "2" ]]; then -FCN_RETURN="`sls_detector_get daclist | sed -e 's/.*\[\(.*\)\].*/\1/' | sed 's/,//g'`" +FCN_RETURN="`sls_detector_get daclist | sed -e 's/.*\[\(.*\)\].*/\\1/' | sed 's/,//g'`" fi if [[ "${cword}" == "3" ]]; then FCN_RETURN="" @@ -611,10 +619,18 @@ return 0 } __dbitclk() { FCN_RETURN="" +if [[ ${IS_GET} -eq 1 ]]; then +if [[ "${cword}" == "2" ]]; then +FCN_RETURN="Hz MHz kHz" +fi +fi if [[ ${IS_GET} -eq 0 ]]; then if [[ "${cword}" == "2" ]]; then FCN_RETURN="" fi +if [[ "${cword}" == "3" ]]; then +FCN_RETURN="Hz MHz kHz" +fi fi return 0 } @@ -648,21 +664,21 @@ __defaultdac() { FCN_RETURN="" if [[ ${IS_GET} -eq 1 ]]; then if [[ "${cword}" == "2" ]]; then -FCN_RETURN="`sls_detector_get daclist | sed -e 's/.*\[\(.*\)\].*/\1/' | sed 's/,//g'`" +FCN_RETURN="`sls_detector_get daclist | sed -e 's/.*\[\(.*\)\].*/\\1/' | sed 's/,//g'`" fi if [[ "${cword}" == "3" ]]; then -FCN_RETURN="`sls_detector_get settingslist | sed -e 's/.*\[\(.*\)\].*/\1/' | sed 's/,//g'`" +FCN_RETURN="`sls_detector_get settingslist | sed -e 's/.*\[\(.*\)\].*/\\1/' | sed 's/,//g'`" fi fi if [[ ${IS_GET} -eq 0 ]]; then if [[ "${cword}" == "2" ]]; then -FCN_RETURN="`sls_detector_get daclist | sed -e 's/.*\[\(.*\)\].*/\1/' | sed 's/,//g'`" +FCN_RETURN="`sls_detector_get daclist | sed -e 's/.*\[\(.*\)\].*/\\1/' | sed 's/,//g'`" fi if [[ "${cword}" == "3" ]]; then FCN_RETURN="" fi if [[ "${cword}" == "4" ]]; then -FCN_RETURN="`sls_detector_get settingslist | sed -e 's/.*\[\(.*\)\].*/\1/' | sed 's/,//g'`" +FCN_RETURN="`sls_detector_get settingslist | sed -e 's/.*\[\(.*\)\].*/\\1/' | sed 's/,//g'`" fi fi return 0 @@ -671,13 +687,13 @@ __defaultpattern() { FCN_RETURN="" if [[ ${IS_GET} -eq 1 ]]; then if [[ "${cword}" == "2" ]]; then -FCN_RETURN="`sls_detector_get daclist | sed -e 's/.*\[\(.*\)\].*/\1/' | sed 's/,//g'`" +FCN_RETURN="`sls_detector_get daclist | sed -e 's/.*\[\(.*\)\].*/\\1/' | sed 's/,//g'`" fi if [[ "${cword}" == "3" ]]; then FCN_RETURN="" fi if [[ "${cword}" == "4" ]]; then -FCN_RETURN="`sls_detector_get settingslist | sed -e 's/.*\[\(.*\)\].*/\1/' | sed 's/,//g'`" +FCN_RETURN="`sls_detector_get settingslist | sed -e 's/.*\[\(.*\)\].*/\\1/' | sed 's/,//g'`" fi fi return 0 @@ -2120,10 +2136,18 @@ return 0 } __runclk() { FCN_RETURN="" +if [[ ${IS_GET} -eq 1 ]]; then +if [[ "${cword}" == "2" ]]; then +FCN_RETURN="Hz MHz kHz" +fi +fi if [[ ${IS_GET} -eq 0 ]]; then if [[ "${cword}" == "2" ]]; then FCN_RETURN="" fi +if [[ "${cword}" == "3" ]]; then +FCN_RETURN="Hz MHz kHz" +fi fi return 0 } @@ -2408,7 +2432,7 @@ __scan() { FCN_RETURN="" if [[ ${IS_GET} -eq 0 ]]; then if [[ "${cword}" == "2" ]]; then -FCN_RETURN="`sls_detector_get daclist | sed -e 's/.*\[\(.*\)\].*/\1/' | sed 's/,//g'`" +FCN_RETURN="`sls_detector_get daclist | sed -e 's/.*\[\(.*\)\].*/\\1/' | sed 's/,//g'`" fi if [[ "${cword}" == "3" ]]; then FCN_RETURN="" @@ -2461,7 +2485,7 @@ __settings() { FCN_RETURN="" if [[ ${IS_GET} -eq 0 ]]; then if [[ "${cword}" == "2" ]]; then -FCN_RETURN="`sls_detector_get settingslist | sed -e 's/.*\[\(.*\)\].*/\1/' | sed 's/,//g'`" +FCN_RETURN="`sls_detector_get settingslist | sed -e 's/.*\[\(.*\)\].*/\\1/' | sed 's/,//g'`" fi fi return 0 @@ -2571,12 +2595,12 @@ __slowadcname() { FCN_RETURN="" if [[ ${IS_GET} -eq 1 ]]; then if [[ "${cword}" == "2" ]]; then -FCN_RETURN="`sls_detector_get daclist | sed -e 's/.*\[\(.*\)\].*/\1/' | sed 's/,//g'`" +FCN_RETURN="`sls_detector_get daclist | sed -e 's/.*\[\(.*\)\].*/\\1/' | sed 's/,//g'`" fi fi if [[ ${IS_GET} -eq 0 ]]; then if [[ "${cword}" == "2" ]]; then -FCN_RETURN="`sls_detector_get daclist | sed -e 's/.*\[\(.*\)\].*/\1/' | sed 's/,//g'`" +FCN_RETURN="`sls_detector_get daclist | sed -e 's/.*\[\(.*\)\].*/\\1/' | sed 's/,//g'`" fi if [[ "${cword}" == "3" ]]; then FCN_RETURN="" @@ -2680,6 +2704,16 @@ return 0 } __syncclk() { FCN_RETURN="" +if [[ ${IS_GET} -eq 1 ]]; then +if [[ "${cword}" == "2" ]]; then +FCN_RETURN="Hz MHz kHz" +fi +fi +if [[ ${IS_GET} -eq 0 ]]; then +if [[ "${cword}" == "2" ]]; then +FCN_RETURN="Hz MHz kHz" +fi +fi return 0 } __temp_10ge() { @@ -2773,13 +2807,13 @@ if [[ "${cword}" == "2" ]]; then FCN_RETURN="" fi if [[ "${cword}" == "3" ]]; then -FCN_RETURN="`sls_detector_get settingslist | sed -e 's/.*\[\(.*\)\].*/\1/' | sed 's/,//g'`" +FCN_RETURN="`sls_detector_get settingslist | sed -e 's/.*\[\(.*\)\].*/\\1/' | sed 's/,//g'`" fi if [[ "${cword}" == "4" ]]; then FCN_RETURN="" fi if [[ "${cword}" == "5" ]]; then -FCN_RETURN="`sls_detector_get settingslist | sed -e 's/.*\[\(.*\)\].*/\1/' | sed 's/,//g'`" +FCN_RETURN="`sls_detector_get settingslist | sed -e 's/.*\[\(.*\)\].*/\\1/' | sed 's/,//g'`" fi fi return 0 @@ -2791,13 +2825,13 @@ if [[ "${cword}" == "2" ]]; then FCN_RETURN="" fi if [[ "${cword}" == "3" ]]; then -FCN_RETURN="`sls_detector_get settingslist | sed -e 's/.*\[\(.*\)\].*/\1/' | sed 's/,//g'`" +FCN_RETURN="`sls_detector_get settingslist | sed -e 's/.*\[\(.*\)\].*/\\1/' | sed 's/,//g'`" fi if [[ "${cword}" == "4" ]]; then FCN_RETURN="" fi if [[ "${cword}" == "5" ]]; then -FCN_RETURN="`sls_detector_get settingslist | sed -e 's/.*\[\(.*\)\].*/\1/' | sed 's/,//g'`" +FCN_RETURN="`sls_detector_get settingslist | sed -e 's/.*\[\(.*\)\].*/\\1/' | sed 's/,//g'`" fi fi return 0 @@ -2806,7 +2840,7 @@ __timing() { FCN_RETURN="" if [[ ${IS_GET} -eq 0 ]]; then if [[ "${cword}" == "2" ]]; then -FCN_RETURN="`sls_detector_get timinglist | sed -e 's/.*\[\(.*\)\].*/\1/' | sed 's/,//g'`" +FCN_RETURN="`sls_detector_get timinglist | sed -e 's/.*\[\(.*\)\].*/\\1/' | sed 's/,//g'`" fi fi return 0 diff --git a/slsDetectorSoftware/generator/autocomplete/zsh_autocomplete.sh b/slsDetectorSoftware/generator/autocomplete/zsh_autocomplete.sh index 92073ccea..953f971d2 100644 --- a/slsDetectorSoftware/generator/autocomplete/zsh_autocomplete.sh +++ b/slsDetectorSoftware/generator/autocomplete/zsh_autocomplete.sh @@ -20,10 +20,18 @@ return 0 } __adcclk() { FCN_RETURN="" +if [[ ${IS_GET} -eq 1 ]]; then +if [[ "${cword}" == "2" ]]; then +FCN_RETURN="Hz MHz kHz" +fi +fi if [[ ${IS_GET} -eq 0 ]]; then if [[ "${cword}" == "2" ]]; then FCN_RETURN="" fi +if [[ "${cword}" == "3" ]]; then +FCN_RETURN="Hz MHz kHz" +fi fi return 0 } @@ -489,12 +497,12 @@ __dacname() { FCN_RETURN="" if [[ ${IS_GET} -eq 1 ]]; then if [[ "${cword}" == "2" ]]; then -FCN_RETURN="`sls_detector_get daclist | sed -e 's/.*\[\(.*\)\].*/\1/' | sed 's/,//g'`" +FCN_RETURN="`sls_detector_get daclist | sed -e 's/.*\[\(.*\)\].*/\\1/' | sed 's/,//g'`" fi fi if [[ ${IS_GET} -eq 0 ]]; then if [[ "${cword}" == "2" ]]; then -FCN_RETURN="`sls_detector_get daclist | sed -e 's/.*\[\(.*\)\].*/\1/' | sed 's/,//g'`" +FCN_RETURN="`sls_detector_get daclist | sed -e 's/.*\[\(.*\)\].*/\\1/' | sed 's/,//g'`" fi if [[ "${cword}" == "3" ]]; then FCN_RETURN="" @@ -535,10 +543,18 @@ return 0 } __dbitclk() { FCN_RETURN="" +if [[ ${IS_GET} -eq 1 ]]; then +if [[ "${cword}" == "2" ]]; then +FCN_RETURN="Hz MHz kHz" +fi +fi if [[ ${IS_GET} -eq 0 ]]; then if [[ "${cword}" == "2" ]]; then FCN_RETURN="" fi +if [[ "${cword}" == "3" ]]; then +FCN_RETURN="Hz MHz kHz" +fi fi return 0 } @@ -572,21 +588,21 @@ __defaultdac() { FCN_RETURN="" if [[ ${IS_GET} -eq 1 ]]; then if [[ "${cword}" == "2" ]]; then -FCN_RETURN="`sls_detector_get daclist | sed -e 's/.*\[\(.*\)\].*/\1/' | sed 's/,//g'`" +FCN_RETURN="`sls_detector_get daclist | sed -e 's/.*\[\(.*\)\].*/\\1/' | sed 's/,//g'`" fi if [[ "${cword}" == "3" ]]; then -FCN_RETURN="`sls_detector_get settingslist | sed -e 's/.*\[\(.*\)\].*/\1/' | sed 's/,//g'`" +FCN_RETURN="`sls_detector_get settingslist | sed -e 's/.*\[\(.*\)\].*/\\1/' | sed 's/,//g'`" fi fi if [[ ${IS_GET} -eq 0 ]]; then if [[ "${cword}" == "2" ]]; then -FCN_RETURN="`sls_detector_get daclist | sed -e 's/.*\[\(.*\)\].*/\1/' | sed 's/,//g'`" +FCN_RETURN="`sls_detector_get daclist | sed -e 's/.*\[\(.*\)\].*/\\1/' | sed 's/,//g'`" fi if [[ "${cword}" == "3" ]]; then FCN_RETURN="" fi if [[ "${cword}" == "4" ]]; then -FCN_RETURN="`sls_detector_get settingslist | sed -e 's/.*\[\(.*\)\].*/\1/' | sed 's/,//g'`" +FCN_RETURN="`sls_detector_get settingslist | sed -e 's/.*\[\(.*\)\].*/\\1/' | sed 's/,//g'`" fi fi return 0 @@ -595,13 +611,13 @@ __defaultpattern() { FCN_RETURN="" if [[ ${IS_GET} -eq 1 ]]; then if [[ "${cword}" == "2" ]]; then -FCN_RETURN="`sls_detector_get daclist | sed -e 's/.*\[\(.*\)\].*/\1/' | sed 's/,//g'`" +FCN_RETURN="`sls_detector_get daclist | sed -e 's/.*\[\(.*\)\].*/\\1/' | sed 's/,//g'`" fi if [[ "${cword}" == "3" ]]; then FCN_RETURN="" fi if [[ "${cword}" == "4" ]]; then -FCN_RETURN="`sls_detector_get settingslist | sed -e 's/.*\[\(.*\)\].*/\1/' | sed 's/,//g'`" +FCN_RETURN="`sls_detector_get settingslist | sed -e 's/.*\[\(.*\)\].*/\\1/' | sed 's/,//g'`" fi fi return 0 @@ -2044,10 +2060,18 @@ return 0 } __runclk() { FCN_RETURN="" +if [[ ${IS_GET} -eq 1 ]]; then +if [[ "${cword}" == "2" ]]; then +FCN_RETURN="Hz MHz kHz" +fi +fi if [[ ${IS_GET} -eq 0 ]]; then if [[ "${cword}" == "2" ]]; then FCN_RETURN="" fi +if [[ "${cword}" == "3" ]]; then +FCN_RETURN="Hz MHz kHz" +fi fi return 0 } @@ -2332,7 +2356,7 @@ __scan() { FCN_RETURN="" if [[ ${IS_GET} -eq 0 ]]; then if [[ "${cword}" == "2" ]]; then -FCN_RETURN="`sls_detector_get daclist | sed -e 's/.*\[\(.*\)\].*/\1/' | sed 's/,//g'`" +FCN_RETURN="`sls_detector_get daclist | sed -e 's/.*\[\(.*\)\].*/\\1/' | sed 's/,//g'`" fi if [[ "${cword}" == "3" ]]; then FCN_RETURN="" @@ -2385,7 +2409,7 @@ __settings() { FCN_RETURN="" if [[ ${IS_GET} -eq 0 ]]; then if [[ "${cword}" == "2" ]]; then -FCN_RETURN="`sls_detector_get settingslist | sed -e 's/.*\[\(.*\)\].*/\1/' | sed 's/,//g'`" +FCN_RETURN="`sls_detector_get settingslist | sed -e 's/.*\[\(.*\)\].*/\\1/' | sed 's/,//g'`" fi fi return 0 @@ -2495,12 +2519,12 @@ __slowadcname() { FCN_RETURN="" if [[ ${IS_GET} -eq 1 ]]; then if [[ "${cword}" == "2" ]]; then -FCN_RETURN="`sls_detector_get daclist | sed -e 's/.*\[\(.*\)\].*/\1/' | sed 's/,//g'`" +FCN_RETURN="`sls_detector_get daclist | sed -e 's/.*\[\(.*\)\].*/\\1/' | sed 's/,//g'`" fi fi if [[ ${IS_GET} -eq 0 ]]; then if [[ "${cword}" == "2" ]]; then -FCN_RETURN="`sls_detector_get daclist | sed -e 's/.*\[\(.*\)\].*/\1/' | sed 's/,//g'`" +FCN_RETURN="`sls_detector_get daclist | sed -e 's/.*\[\(.*\)\].*/\\1/' | sed 's/,//g'`" fi if [[ "${cword}" == "3" ]]; then FCN_RETURN="" @@ -2604,6 +2628,16 @@ return 0 } __syncclk() { FCN_RETURN="" +if [[ ${IS_GET} -eq 1 ]]; then +if [[ "${cword}" == "2" ]]; then +FCN_RETURN="Hz MHz kHz" +fi +fi +if [[ ${IS_GET} -eq 0 ]]; then +if [[ "${cword}" == "2" ]]; then +FCN_RETURN="Hz MHz kHz" +fi +fi return 0 } __temp_10ge() { @@ -2697,13 +2731,13 @@ if [[ "${cword}" == "2" ]]; then FCN_RETURN="" fi if [[ "${cword}" == "3" ]]; then -FCN_RETURN="`sls_detector_get settingslist | sed -e 's/.*\[\(.*\)\].*/\1/' | sed 's/,//g'`" +FCN_RETURN="`sls_detector_get settingslist | sed -e 's/.*\[\(.*\)\].*/\\1/' | sed 's/,//g'`" fi if [[ "${cword}" == "4" ]]; then FCN_RETURN="" fi if [[ "${cword}" == "5" ]]; then -FCN_RETURN="`sls_detector_get settingslist | sed -e 's/.*\[\(.*\)\].*/\1/' | sed 's/,//g'`" +FCN_RETURN="`sls_detector_get settingslist | sed -e 's/.*\[\(.*\)\].*/\\1/' | sed 's/,//g'`" fi fi return 0 @@ -2715,13 +2749,13 @@ if [[ "${cword}" == "2" ]]; then FCN_RETURN="" fi if [[ "${cword}" == "3" ]]; then -FCN_RETURN="`sls_detector_get settingslist | sed -e 's/.*\[\(.*\)\].*/\1/' | sed 's/,//g'`" +FCN_RETURN="`sls_detector_get settingslist | sed -e 's/.*\[\(.*\)\].*/\\1/' | sed 's/,//g'`" fi if [[ "${cword}" == "4" ]]; then FCN_RETURN="" fi if [[ "${cword}" == "5" ]]; then -FCN_RETURN="`sls_detector_get settingslist | sed -e 's/.*\[\(.*\)\].*/\1/' | sed 's/,//g'`" +FCN_RETURN="`sls_detector_get settingslist | sed -e 's/.*\[\(.*\)\].*/\\1/' | sed 's/,//g'`" fi fi return 0 @@ -2730,7 +2764,7 @@ __timing() { FCN_RETURN="" if [[ ${IS_GET} -eq 0 ]]; then if [[ "${cword}" == "2" ]]; then -FCN_RETURN="`sls_detector_get timinglist | sed -e 's/.*\[\(.*\)\].*/\1/' | sed 's/,//g'`" +FCN_RETURN="`sls_detector_get timinglist | sed -e 's/.*\[\(.*\)\].*/\\1/' | sed 's/,//g'`" fi fi return 0 diff --git a/slsDetectorSoftware/generator/commands.yaml b/slsDetectorSoftware/generator/commands.yaml index 20f94b12a..9e069f830 100644 --- a/slsDetectorSoftware/generator/commands.yaml +++ b/slsDetectorSoftware/generator/commands.yaml @@ -2,6 +2,56 @@ # detectors: MYTHEN3 ################# TEMPLATES ################# +FREQ_COMMAND: + infer_action: true + help: "" + template: true + actions: + GET: + require_det_id: true + function: '' + args: + - argc: 0 + output: [ OutString(t) ] + - argc: 1 + arg_types: [ special::freq_unit ] + output: [ "OutString(t , args[0])" ] + PUT: + function: '' + require_det_id: true + input: [ converted_freq ] + input_types: [ defs::Hz ] + args: + - argc: 1 + arg_types: [ std::string ] + + separate_freq_units: + input: 'args[0]' + output: [ converted_freq, unit ] + output: [ 'args[0]' ] + - argc: 2 + arg_types: [ int, special::freq_unit ] + + convert_to_freq: + input: [ 'args[0]', 'args[1]' ] + output: converted_freq + output: [ 'args[0]', 'args[1]' ] + +FREQ_GET_COMMAND: + infer_action: true + help: "" + template: true + actions: + GET: + require_det_id: true + function: '' + args: + - argc: 0 + output: [ OutString(t) ] + - argc: 1 + arg_types: [ special::freq_unit ] + output: [ "OutString(t , args[0])" ] + TIME_COMMAND: infer_action: true help: "" @@ -401,6 +451,44 @@ CTB_GET_INDEX: ################# COMMANDS ################################## +################# FREQ_COMMAND ############# +adcclk: + help: "[n_clk] [(optional unit) Hz(default)|kHz|MHz]\n\t[Ctb][Xilinx Ctb] ADC clock frequency." + inherit_actions: FREQ_COMMAND + actions: + GET: + function: getADCClock + PUT: + function: setADCClock + +runclk: + help: "[n_clk] [(optional unit) Hz(default)|kHz|MHz]\n\t[Ctb][Xilinx Ctb] Run clock frequency." + inherit_actions: FREQ_COMMAND + actions: + GET: + function: getRUNClock + PUT: + function: setRUNClock + + +dbitclk: + help: "[n_clk] [(optional unit) Hz(default)|kHz|MHz]\n\t[Ctb][Xilinx Ctb] Clock for latching the digital bits." + inherit_actions: FREQ_COMMAND + actions: + GET: + function: getDBITClock + PUT: + function: setDBITClock + +################# FREQ_GET_COMMAND ############# + +syncclk: + inherit_actions: FREQ_GET_COMMAND + help: "[n_clk] [(optional unit) Hz(default)|kHz|MHz]\n\t[Ctb] Sync clock." + actions: + GET: + function: getSYNCClock + ################# TIME_COMMAND ############# period: @@ -1243,23 +1331,6 @@ asamples: PUT: function: setNumberOfAnalogSamples -adcclk: - help: "[n_clk in MHz]\n\t[Ctb] ADC clock frequency in MHz.\n\t[xilinx Ctb] ADC clock frequency in kHz." - inherit_actions: INTEGER_COMMAND_VEC_ID - actions: - GET: - function: getADCClock - PUT: - function: setADCClock - -runclk: - help: "[n_clk in MHz]\n\t[Ctb] Run clock in MHz.\n\t[xilinx Ctb] Run clock in kHz." - inherit_actions: INTEGER_COMMAND_VEC_ID - actions: - GET: - function: getRUNClock - PUT: - function: setRUNClock dsamples: help: "[n_value]\n\t[Ctb] Number of digital samples expected." @@ -1289,15 +1360,6 @@ romode: function: setReadoutMode input_types: [ defs::readoutMode ] -dbitclk: - help: "[n_clk in MHz]\n\t[Ctb] Clock for latching the digital bits in MHz.\n\t[xilinx Ctb] Clock for latching the digital bits in kHz." - inherit_actions: INTEGER_COMMAND_VEC_ID - actions: - GET: - function: getDBITClock - PUT: - function: setDBITClock - extsampling: help: "[0, 1]\n\t[Ctb] Enable for external sampling signal for digital data to signal by extsampling src command. For advanced users only." inherit_actions: INTEGER_COMMAND_VEC_ID @@ -1912,19 +1974,12 @@ burstsl: GET: function: getNumberOfBurstsLeft -syncclk: - inherit_actions: GET_COMMAND - help: "[n_clk in MHz]\n\t[Ctb] Sync clock in MHz." - actions: - GET: - function: getSYNCClock - patfname: inherit_actions: GET_COMMAND help: "\n\t[Ctb][Mythen3][Xilinx Ctb] Gets the pattern file name including path of the last pattern uploaded. Returns an empty if nothing was uploaded or via a server default file" actions: GET: - function: getPatterFileName + function: getPatternFileName lastclient: inherit_actions: GET_COMMAND diff --git a/slsDetectorSoftware/generator/commands_parser/commands_parser.py b/slsDetectorSoftware/generator/commands_parser/commands_parser.py index 9a11cd789..576cbfa21 100644 --- a/slsDetectorSoftware/generator/commands_parser/commands_parser.py +++ b/slsDetectorSoftware/generator/commands_parser/commands_parser.py @@ -50,7 +50,6 @@ class CommandParser: if len(arg['input_types']) != len(arg['input']): raise ValueError(f'Argument {arg} does not have the correct number of inputs') if 'separate_time_units' in arg: - if arg['separate_time_units']['input'] == "": raise ValueError(f'Argument {arg} does not have the correct number of inputs for separate_time_units') if len(arg['separate_time_units']['output']) != 2: @@ -60,6 +59,16 @@ class CommandParser: raise ValueError(f'Argument {arg} does not have the correct number of inputs for convert_to_time') if len(arg['convert_to_time']['output']) == "": raise ValueError(f'Argument {arg} does not have the correct number of outputs for convert_to_time') + if 'separate_freq_units' in arg: + if arg['separate_freq_units']['input'] == "": + raise ValueError(f'Argument {arg} does not have the correct number of inputs for separate_freq_units') + if len(arg['separate_freq_units']['output']) != 2: + raise ValueError(f'Argument {arg} does not have the correct number of outputs for separate_freq_units') + if 'convert_to_freq' in arg: + if len(arg['convert_to_freq']['input']) != 2: + raise ValueError(f'Argument {arg} does not have the correct number of inputs for convert_to_freq') + if len(arg['convert_to_freq']['output']) == "": + raise ValueError(f'Argument {arg} does not have the correct number of outputs for convert_to_freq') # if infer_action: # if arg['argc'] in self.argc_set: # raise ValueError(f'Argument {arg} has a duplicate argc') diff --git a/slsDetectorSoftware/generator/cpp_codegen/codegen.py b/slsDetectorSoftware/generator/cpp_codegen/codegen.py index fef9959d0..a9e875b09 100644 --- a/slsDetectorSoftware/generator/cpp_codegen/codegen.py +++ b/slsDetectorSoftware/generator/cpp_codegen/codegen.py @@ -142,6 +142,16 @@ class CodeGenerator: if 'convert_to_time' in arg and arg['convert_to_time']: self.write_line(f'auto {arg["convert_to_time"]["output"]} = ' f'StringTo < time::ns > ({", ".join(arg["convert_to_time"]["input"])});') + if 'separate_freq_units' in arg and arg['separate_freq_units']: + self.write_line(f'std::string tmp_freq({arg["separate_freq_units"]["input"]});') + self.write_line(f'std::string {arg["separate_freq_units"]["output"][1]}' + f' = RemoveUnit(tmp_freq);') + self.write_line(f'auto {arg["separate_freq_units"]["output"][0]} = ' + f'StringTo < defs::Hz > (tmp_freq,' + f' {arg["separate_freq_units"]["output"][1]});') + if 'convert_to_freq' in arg and arg['convert_to_freq']: + self.write_line(f'auto {arg["convert_to_freq"]["output"]} = ' + f'StringTo < defs::Hz > ({", ".join(arg["convert_to_freq"]["input"])});') input_arguments = [] if 'exceptions' in arg: for exception in arg['exceptions']: diff --git a/slsDetectorSoftware/generator/extended_commands.yaml b/slsDetectorSoftware/generator/extended_commands.yaml index 9dd24bb5d..c29c13bc5 100644 --- a/slsDetectorSoftware/generator/extended_commands.yaml +++ b/slsDetectorSoftware/generator/extended_commands.yaml @@ -86,28 +86,69 @@ adcclk: - OutString(t) require_det_id: true store_result_in_t: true + - arg_types: + - special::freq_unit + argc: 1 + cast_input: [] + check_det_id: false + convert_det_id: true + function: getADCClock + input: [] + input_types: [] + output: + - OutString(t , args[0]) + require_det_id: true + store_result_in_t: true PUT: args: - arg_types: - - int + - std::string argc: 1 cast_input: - - true + - false check_det_id: false convert_det_id: true function: setADCClock input: - - args[0] + - converted_freq input_types: - - int + - defs::Hz output: - - args.front() + - args[0] + require_det_id: true + separate_freq_units: + input: args[0] + output: + - converted_freq + - unit + store_result_in_t: false + - arg_types: + - int + - special::freq_unit + argc: 2 + cast_input: + - false + check_det_id: false + convert_det_id: true + convert_to_freq: + input: + - args[0] + - args[1] + output: converted_freq + function: setADCClock + input: + - converted_freq + input_types: + - defs::Hz + output: + - args[0] + - args[1] require_det_id: true store_result_in_t: false command_name: adcclk function_alias: adcclk - help: "[n_clk in MHz]\n\t[Ctb] ADC clock frequency in MHz.\n\t[xilinx Ctb] ADC clock\ - \ frequency in kHz." + help: "[n_clk] [(optional unit) Hz(default)|kHz|MHz]\n\t[Ctb][Xilinx Ctb] ADC clock\ + \ frequency." infer_action: true template: true adcenable: @@ -2060,28 +2101,69 @@ dbitclk: - OutString(t) require_det_id: true store_result_in_t: true + - arg_types: + - special::freq_unit + argc: 1 + cast_input: [] + check_det_id: false + convert_det_id: true + function: getDBITClock + input: [] + input_types: [] + output: + - OutString(t , args[0]) + require_det_id: true + store_result_in_t: true PUT: args: - arg_types: - - int + - std::string argc: 1 cast_input: - - true + - false check_det_id: false convert_det_id: true function: setDBITClock input: - - args[0] + - converted_freq input_types: - - int + - defs::Hz output: - - args.front() + - args[0] + require_det_id: true + separate_freq_units: + input: args[0] + output: + - converted_freq + - unit + store_result_in_t: false + - arg_types: + - int + - special::freq_unit + argc: 2 + cast_input: + - false + check_det_id: false + convert_det_id: true + convert_to_freq: + input: + - args[0] + - args[1] + output: converted_freq + function: setDBITClock + input: + - converted_freq + input_types: + - defs::Hz + output: + - args[0] + - args[1] require_det_id: true store_result_in_t: false command_name: dbitclk function_alias: dbitclk - help: "[n_clk in MHz]\n\t[Ctb] Clock for latching the digital bits in MHz.\n\t[xilinx\ - \ Ctb] Clock for latching the digital bits in kHz." + help: "[n_clk] [(optional unit) Hz(default)|kHz|MHz]\n\t[Ctb][Xilinx Ctb] Clock\ + \ for latching the digital bits." infer_action: true template: true dbitphase: @@ -5788,7 +5870,7 @@ patfname: cast_input: [] check_det_id: false convert_det_id: true - function: getPatterFileName + function: getPatternFileName input: [] input_types: [] output: @@ -8140,27 +8222,69 @@ runclk: - OutString(t) require_det_id: true store_result_in_t: true + - arg_types: + - special::freq_unit + argc: 1 + cast_input: [] + check_det_id: false + convert_det_id: true + function: getRUNClock + input: [] + input_types: [] + output: + - OutString(t , args[0]) + require_det_id: true + store_result_in_t: true PUT: args: - arg_types: - - int + - std::string argc: 1 cast_input: - - true + - false check_det_id: false convert_det_id: true function: setRUNClock input: - - args[0] + - converted_freq input_types: - - int + - defs::Hz output: - - args.front() + - args[0] + require_det_id: true + separate_freq_units: + input: args[0] + output: + - converted_freq + - unit + store_result_in_t: false + - arg_types: + - int + - special::freq_unit + argc: 2 + cast_input: + - false + check_det_id: false + convert_det_id: true + convert_to_freq: + input: + - args[0] + - args[1] + output: converted_freq + function: setRUNClock + input: + - converted_freq + input_types: + - defs::Hz + output: + - args[0] + - args[1] require_det_id: true store_result_in_t: false command_name: runclk function_alias: runclk - help: "[n_clk in MHz]\n\t[Ctb] Run clock in MHz.\n\t[xilinx Ctb] Run clock in kHz." + help: "[n_clk] [(optional unit) Hz(default)|kHz|MHz]\n\t[Ctb][Xilinx Ctb] Run clock\ + \ frequency." infer_action: true template: true runtime: @@ -10575,9 +10699,22 @@ syncclk: - OutString(t) require_det_id: true store_result_in_t: true + - arg_types: + - special::freq_unit + argc: 1 + cast_input: [] + check_det_id: false + convert_det_id: true + function: getSYNCClock + input: [] + input_types: [] + output: + - OutString(t , args[0]) + require_det_id: true + store_result_in_t: true command_name: syncclk function_alias: syncclk - help: "[n_clk in MHz]\n\t[Ctb] Sync clock in MHz." + help: "[n_clk] [(optional unit) Hz(default)|kHz|MHz]\n\t[Ctb] Sync clock." infer_action: true template: true temp_10ge: diff --git a/slsDetectorSoftware/generator/gen_commands.py b/slsDetectorSoftware/generator/gen_commands.py index 45dbc878f..4a12ee1af 100644 --- a/slsDetectorSoftware/generator/gen_commands.py +++ b/slsDetectorSoftware/generator/gen_commands.py @@ -122,7 +122,25 @@ def generate( f'StringTo < time::ns > ({", ".join(arg["convert_to_time"]["input"])});') codegen.write_line( f'}} catch (...) {{ throw RuntimeError("Could not convert arguments to time::ns");}}') + elif 'separate_freq_units' in arg and arg['separate_freq_units']: + codegen.write_line(f'try {{') + # TODO: refactor this repeating code + codegen.write_line(f'std::string tmp_freq({arg["separate_freq_units"]["input"]});') + codegen.write_line(f'std::string {arg["separate_freq_units"]["output"][1]}' + f' = RemoveUnit(tmp_freq);') + codegen.write_line(f'auto {arg["separate_freq_units"]["output"][0]} = ' + f'StringTo < defs::Hz > (tmp_freq,' + f' {arg["separate_freq_units"]["output"][1]});') + codegen.write_line( + f'}} catch (...) {{ throw RuntimeError("Could not convert argument to defs::Hz");}}') + elif 'convert_to_freq' in arg and arg['convert_to_freq']: + codegen.write_line(f'try {{') + + codegen.write_line( + f'StringTo < defs::Hz > ({", ".join(arg["convert_to_freq"]["input"])});') + codegen.write_line( + f'}} catch (...) {{ throw RuntimeError("Could not convert arguments to defs::Hz");}}') for i in range(len(arg['input'])): if not arg['cast_input'][i]: continue diff --git a/slsDetectorSoftware/generator/readme.md b/slsDetectorSoftware/generator/readme.md index d480d6c43..2e7054660 100644 --- a/slsDetectorSoftware/generator/readme.md +++ b/slsDetectorSoftware/generator/readme.md @@ -302,7 +302,13 @@ write_arg in codegen reads the argument fields and generate c++ code accordingly std::string $output[1]$ = RemoveUnit(tmp_time); auto $output[0]$ = StringTo(tmp_time, $output[1]$); ``` -- convert_to_time: takes three parameters: input[0], input[1], output +- separate_freq_units: takes three parameters: input, output[0], output[1] each one is a variable name + ```cpp + std::string tmp_freq($input$); + std::string $output[1]$ = RemoveUnit(tmp_freq); + auto $output[0]$ = StringTo(tmp_freq, $output[1]$); + ``` +- convert_to_time and convert_to_freq: takes three parameters: input[0], input[1], output ```cpp auto output = StringTo(input[0], input[1]); ``` diff --git a/slsDetectorSoftware/include/sls/Detector.h b/slsDetectorSoftware/include/sls/Detector.h index a44a46e5f..d107370de 100644 --- a/slsDetectorSoftware/include/sls/Detector.h +++ b/slsDetectorSoftware/include/sls/Detector.h @@ -1613,20 +1613,26 @@ class Detector { /** [CTB] */ void setNumberOfAnalogSamples(int value, Positions pos = {}); - /** [CTB] in MHz, [XCTB] in kHz */ - Result getADCClock(Positions pos = {}) const; + /** [CTB][XCTB] */ + Result getADCClock(Positions pos = {}) const; - /** [CTB] in MHz, [XCTB] in kHz */ - void setADCClock(int value_in_MHz, Positions pos = {}); + /** [CTB][XCTB] */ + void setADCClock(defs::Hz val, Positions pos = {}); - /** [CTB] in MHz, [XCTB] in kHz */ - Result getRUNClock(Positions pos = {}) const; + /** [CTB][XCTB] */ + Result getRUNClock(Positions pos = {}) const; - /** [CTB] in MHz, [XCTB] in kHz */ - void setRUNClock(int value_in_MHz, Positions pos = {}); + /** [CTB][XCTB] */ + void setRUNClock(defs::Hz val, Positions pos = {}); - /** [CTB] in MHZ */ - Result getSYNCClock(Positions pos = {}) const; + /** [CTB][XCTB] */ + Result getDBITClock(Positions pos = {}) const; + + /** [CTB][XCTB] */ + void setDBITClock(defs::Hz val, Positions pos = {}); + + /** [CTB][XCTB] */ + Result getSYNCClock(Positions pos = {}) const; /** gets list of power enums */ std::vector getPowerList() const; @@ -1721,12 +1727,6 @@ class Detector { */ void setReadoutMode(defs::readoutMode value, Positions pos = {}); - /** [CTB] in MHz, [XCTB] in kHz */ - Result getDBITClock(Positions pos = {}) const; - - /** [CTB] in MHz, [XCTB] in kHz */ - void setDBITClock(int value_in_MHz, Positions pos = {}); - /** [CTB] */ Result getExternalSamplingSource(Positions pos = {}) const; @@ -1934,7 +1934,7 @@ class Detector { /** [CTB][Mythen3][Xilinx CTB] Gets the pattern file name including path of * the last pattern uploaded. \n Returns an empty if nothing was uploaded or * via a server default file*/ - Result getPatterFileName(Positions pos = {}) const; + Result getPatternFileName(Positions pos = {}) const; /** [CTB][Mythen3][Xilinx CTB] Loads ASCII pattern file directly to server * (instead of executing line by line)*/ diff --git a/slsDetectorSoftware/include/sls/Result.h b/slsDetectorSoftware/include/sls/Result.h index 0cb937408..5554bdaa8 100644 --- a/slsDetectorSoftware/include/sls/Result.h +++ b/slsDetectorSoftware/include/sls/Result.h @@ -38,6 +38,7 @@ template > class Result { template ::value && (std::is_same::value || + std::is_same::value || std::is_same::value)>::type> Result(const Result &from) { vec.reserve(from.size()); @@ -49,6 +50,7 @@ template > class Result { template ::value && (std::is_same::value || + std::is_same::value || std::is_same::value)>::type> Result(Result &from) { vec.reserve(from.size()); @@ -60,6 +62,7 @@ template > class Result { template ::value && (std::is_same::value || + std::is_same::value || std::is_same::value)>::type> Result(Result &&from) { vec.reserve(from.size()); diff --git a/slsDetectorSoftware/src/Caller.cpp b/slsDetectorSoftware/src/Caller.cpp index 17405241e..1e72aba17 100644 --- a/slsDetectorSoftware/src/Caller.cpp +++ b/slsDetectorSoftware/src/Caller.cpp @@ -72,34 +72,46 @@ std::string Caller::adcclk(int action) { std::ostringstream os; // print help if (action == slsDetectorDefs::HELP_ACTION) { - os << R"V0G0N([n_clk in MHz] - [Ctb] ADC clock frequency in MHz. - [xilinx Ctb] ADC clock frequency in kHz. )V0G0N" + os << R"V0G0N([n_clk] [(optional unit) Hz(default)|kHz|MHz] + [Ctb][Xilinx Ctb] ADC clock frequency. )V0G0N" << std::endl; return os.str(); } // check if action and arguments are valid if (action == slsDetectorDefs::GET_ACTION) { - if (1 && args.size() != 0) { + if (1 && args.size() != 0 && args.size() != 1) { throw RuntimeError("Wrong number of arguments for action GET"); } if (args.size() == 0) { } + if (args.size() == 1) { + } + } else if (action == slsDetectorDefs::PUT_ACTION) { - if (1 && args.size() != 1) { + if (1 && args.size() != 1 && args.size() != 2) { throw RuntimeError("Wrong number of arguments for action PUT"); } if (args.size() == 1) { try { - StringTo(args[0]); + std::string tmp_freq(args[0]); + std::string unit = RemoveUnit(tmp_freq); + auto converted_freq = StringTo(tmp_freq, unit); } catch (...) { - throw RuntimeError("Could not convert argument 0 to int"); + throw RuntimeError("Could not convert argument to defs::Hz"); + } + } + + if (args.size() == 2) { + try { + StringTo(args[0], args[1]); + } catch (...) { + throw RuntimeError("Could not convert arguments to defs::Hz"); } } @@ -117,13 +129,26 @@ std::string Caller::adcclk(int action) { auto t = det->getADCClock(std::vector{det_id}); os << OutString(t) << '\n'; } + + if (args.size() == 1) { + auto t = det->getADCClock(std::vector{det_id}); + os << OutString(t, args[0]) << '\n'; + } } if (action == slsDetectorDefs::PUT_ACTION) { if (args.size() == 1) { - auto arg0 = StringTo(args[0]); - det->setADCClock(arg0, std::vector{det_id}); - os << args.front() << '\n'; + std::string tmp_freq(args[0]); + std::string unit = RemoveUnit(tmp_freq); + auto converted_freq = StringTo(tmp_freq, unit); + det->setADCClock(converted_freq, std::vector{det_id}); + os << args[0] << '\n'; + } + + if (args.size() == 2) { + auto converted_freq = StringTo(args[0], args[1]); + det->setADCClock(converted_freq, std::vector{det_id}); + os << args[0] << args[1] << '\n'; } } @@ -2482,34 +2507,46 @@ std::string Caller::dbitclk(int action) { std::ostringstream os; // print help if (action == slsDetectorDefs::HELP_ACTION) { - os << R"V0G0N([n_clk in MHz] - [Ctb] Clock for latching the digital bits in MHz. - [xilinx Ctb] Clock for latching the digital bits in kHz. )V0G0N" + os << R"V0G0N([n_clk] [(optional unit) Hz(default)|kHz|MHz] + [Ctb][Xilinx Ctb] Clock for latching the digital bits. )V0G0N" << std::endl; return os.str(); } // check if action and arguments are valid if (action == slsDetectorDefs::GET_ACTION) { - if (1 && args.size() != 0) { + if (1 && args.size() != 0 && args.size() != 1) { throw RuntimeError("Wrong number of arguments for action GET"); } if (args.size() == 0) { } + if (args.size() == 1) { + } + } else if (action == slsDetectorDefs::PUT_ACTION) { - if (1 && args.size() != 1) { + if (1 && args.size() != 1 && args.size() != 2) { throw RuntimeError("Wrong number of arguments for action PUT"); } if (args.size() == 1) { try { - StringTo(args[0]); + std::string tmp_freq(args[0]); + std::string unit = RemoveUnit(tmp_freq); + auto converted_freq = StringTo(tmp_freq, unit); } catch (...) { - throw RuntimeError("Could not convert argument 0 to int"); + throw RuntimeError("Could not convert argument to defs::Hz"); + } + } + + if (args.size() == 2) { + try { + StringTo(args[0], args[1]); + } catch (...) { + throw RuntimeError("Could not convert arguments to defs::Hz"); } } @@ -2527,13 +2564,26 @@ std::string Caller::dbitclk(int action) { auto t = det->getDBITClock(std::vector{det_id}); os << OutString(t) << '\n'; } + + if (args.size() == 1) { + auto t = det->getDBITClock(std::vector{det_id}); + os << OutString(t, args[0]) << '\n'; + } } if (action == slsDetectorDefs::PUT_ACTION) { if (args.size() == 1) { - auto arg0 = StringTo(args[0]); - det->setDBITClock(arg0, std::vector{det_id}); - os << args.front() << '\n'; + std::string tmp_freq(args[0]); + std::string unit = RemoveUnit(tmp_freq); + auto converted_freq = StringTo(tmp_freq, unit); + det->setDBITClock(converted_freq, std::vector{det_id}); + os << args[0] << '\n'; + } + + if (args.size() == 2) { + auto converted_freq = StringTo(args[0], args[1]); + det->setDBITClock(converted_freq, std::vector{det_id}); + os << args[0] << args[1] << '\n'; } } @@ -7312,7 +7362,7 @@ std::string Caller::patfname(int action) { // generate code for each action if (action == slsDetectorDefs::GET_ACTION) { if (args.size() == 0) { - auto t = det->getPatterFileName(std::vector{det_id}); + auto t = det->getPatternFileName(std::vector{det_id}); os << OutString(t) << '\n'; } } @@ -9909,34 +9959,46 @@ std::string Caller::runclk(int action) { std::ostringstream os; // print help if (action == slsDetectorDefs::HELP_ACTION) { - os << R"V0G0N([n_clk in MHz] - [Ctb] Run clock in MHz. - [xilinx Ctb] Run clock in kHz. )V0G0N" + os << R"V0G0N([n_clk] [(optional unit) Hz(default)|kHz|MHz] + [Ctb][Xilinx Ctb] Run clock frequency. )V0G0N" << std::endl; return os.str(); } // check if action and arguments are valid if (action == slsDetectorDefs::GET_ACTION) { - if (1 && args.size() != 0) { + if (1 && args.size() != 0 && args.size() != 1) { throw RuntimeError("Wrong number of arguments for action GET"); } if (args.size() == 0) { } + if (args.size() == 1) { + } + } else if (action == slsDetectorDefs::PUT_ACTION) { - if (1 && args.size() != 1) { + if (1 && args.size() != 1 && args.size() != 2) { throw RuntimeError("Wrong number of arguments for action PUT"); } if (args.size() == 1) { try { - StringTo(args[0]); + std::string tmp_freq(args[0]); + std::string unit = RemoveUnit(tmp_freq); + auto converted_freq = StringTo(tmp_freq, unit); } catch (...) { - throw RuntimeError("Could not convert argument 0 to int"); + throw RuntimeError("Could not convert argument to defs::Hz"); + } + } + + if (args.size() == 2) { + try { + StringTo(args[0], args[1]); + } catch (...) { + throw RuntimeError("Could not convert arguments to defs::Hz"); } } @@ -9954,13 +10016,26 @@ std::string Caller::runclk(int action) { auto t = det->getRUNClock(std::vector{det_id}); os << OutString(t) << '\n'; } + + if (args.size() == 1) { + auto t = det->getRUNClock(std::vector{det_id}); + os << OutString(t, args[0]) << '\n'; + } } if (action == slsDetectorDefs::PUT_ACTION) { if (args.size() == 1) { - auto arg0 = StringTo(args[0]); - det->setRUNClock(arg0, std::vector{det_id}); - os << args.front() << '\n'; + std::string tmp_freq(args[0]); + std::string unit = RemoveUnit(tmp_freq); + auto converted_freq = StringTo(tmp_freq, unit); + det->setRUNClock(converted_freq, std::vector{det_id}); + os << args[0] << '\n'; + } + + if (args.size() == 2) { + auto converted_freq = StringTo(args[0], args[1]); + det->setRUNClock(converted_freq, std::vector{det_id}); + os << args[0] << args[1] << '\n'; } } @@ -13062,21 +13137,24 @@ std::string Caller::syncclk(int action) { std::ostringstream os; // print help if (action == slsDetectorDefs::HELP_ACTION) { - os << R"V0G0N([n_clk in MHz] - [Ctb] Sync clock in MHz. )V0G0N" + os << R"V0G0N([n_clk] [(optional unit) Hz(default)|kHz|MHz] + [Ctb] Sync clock. )V0G0N" << std::endl; return os.str(); } // check if action and arguments are valid if (action == slsDetectorDefs::GET_ACTION) { - if (1 && args.size() != 0) { + if (1 && args.size() != 0 && args.size() != 1) { throw RuntimeError("Wrong number of arguments for action GET"); } if (args.size() == 0) { } + if (args.size() == 1) { + } + } else { @@ -13091,6 +13169,11 @@ std::string Caller::syncclk(int action) { auto t = det->getSYNCClock(std::vector{det_id}); os << OutString(t) << '\n'; } + + if (args.size() == 1) { + auto t = det->getSYNCClock(std::vector{det_id}); + os << OutString(t, args[0]) << '\n'; + } } return os.str(); diff --git a/slsDetectorSoftware/src/Caller.h b/slsDetectorSoftware/src/Caller.h index ce9e7cc93..d35ffe569 100644 --- a/slsDetectorSoftware/src/Caller.h +++ b/slsDetectorSoftware/src/Caller.h @@ -54,6 +54,9 @@ class Caller { return ToString(value, unit); } + std::string OutString(const Result &value, + const std::string &unit); + std::vector getAllCommands(); std::map GetDeprecatedCommands(); std::string list(int action); @@ -421,6 +424,7 @@ class Caller { defs::dacIndex parseDacIndex(int argIndex, bool isCtb); bool parseMV(int argIndex); defs::powerIndex parsePowerIndex(int argIndex); + defs::FrequencyUnit parseFrequencyUnit(const std::string &s); FunctionMap functions{ {"list", &Caller::list}, diff --git a/slsDetectorSoftware/src/CallerSpecial.cpp b/slsDetectorSoftware/src/CallerSpecial.cpp index cf339ee5d..50cd1e72d 100644 --- a/slsDetectorSoftware/src/CallerSpecial.cpp +++ b/slsDetectorSoftware/src/CallerSpecial.cpp @@ -11,6 +11,14 @@ namespace sls { // some helper functions to print +std::string Caller::OutString(const Result &value, + const std::string &unit) { + auto u = parseFrequencyUnit(unit); + if (value.equal()) + return ToString(value.front(), u); + return ToString(value, u); +} + std::vector Caller::getAllCommands() { std::vector ret; for (auto it : functions) @@ -2105,4 +2113,21 @@ std::string Caller::powervalues(int action) { return os.str(); } +defs::FrequencyUnit Caller::parseFrequencyUnit(const std::string &unit) { + auto unitLower = [&] { + std::string result = unit; + std::transform(result.begin(), result.end(), result.begin(), + [](unsigned char c) { return std::tolower(c); }); + return result; + }(); + if (unitLower == "hz") + return defs::FrequencyUnit::Hz; + if (unitLower == "khz") + return defs::FrequencyUnit::kHz; + if (unitLower == "mhz") + return defs::FrequencyUnit::MHz; + + throw std::runtime_error("Unknown frequency unit: " + unit); +} + } // namespace sls \ No newline at end of file diff --git a/slsDetectorSoftware/src/Detector.cpp b/slsDetectorSoftware/src/Detector.cpp index a6bd47a2f..01e9f5a44 100644 --- a/slsDetectorSoftware/src/Detector.cpp +++ b/slsDetectorSoftware/src/Detector.cpp @@ -2144,25 +2144,34 @@ void Detector::setNumberOfAnalogSamples(int value, Positions pos) { pimpl->Parallel(&Module::setNumberOfAnalogSamples, pos, value); } -Result Detector::getADCClock(Positions pos) const { +Result Detector::getADCClock(Positions pos) const { return pimpl->Parallel(&Module::getClockFrequency, pos, defs::ADC_CLOCK); } -void Detector::setADCClock(int value_in_MHz, Positions pos) { +void Detector::setADCClock(defs::Hz val, Positions pos) { pimpl->Parallel(&Module::setClockFrequency, pos, defs::ADC_CLOCK, - value_in_MHz); + val.value); } -Result Detector::getRUNClock(Positions pos) const { +Result Detector::getRUNClock(Positions pos) const { return pimpl->Parallel(&Module::getClockFrequency, pos, defs::RUN_CLOCK); } -void Detector::setRUNClock(int value_in_MHz, Positions pos) { +void Detector::setRUNClock(defs::Hz val, Positions pos) { pimpl->Parallel(&Module::setClockFrequency, pos, defs::RUN_CLOCK, - value_in_MHz); + val.value); } -Result Detector::getSYNCClock(Positions pos) const { +Result Detector::getDBITClock(Positions pos) const { + return pimpl->Parallel(&Module::getClockFrequency, pos, defs::DBIT_CLOCK); +} + +void Detector::setDBITClock(defs::Hz val, Positions pos) { + pimpl->Parallel(&Module::setClockFrequency, pos, defs::DBIT_CLOCK, + val.value); +} + +Result Detector::getSYNCClock(Positions pos) const { return pimpl->Parallel(&Module::getClockFrequency, pos, defs::SYNC_CLOCK); } @@ -2310,15 +2319,6 @@ void Detector::setReadoutMode(defs::readoutMode value, Positions pos) { pimpl->Parallel(&Module::setReadoutMode, pos, value); } -Result Detector::getDBITClock(Positions pos) const { - return pimpl->Parallel(&Module::getClockFrequency, pos, defs::DBIT_CLOCK); -} - -void Detector::setDBITClock(int value_in_MHz, Positions pos) { - pimpl->Parallel(&Module::setClockFrequency, pos, defs::DBIT_CLOCK, - value_in_MHz); -} - Result Detector::getSlowADC(defs::dacIndex index, Positions pos) const { if (index < defs::SLOW_ADC0 || index > defs::SLOW_ADC7) { throw RuntimeError("Unknown Slow ADC Index"); @@ -2609,8 +2609,8 @@ void Detector::configureTransceiver(Positions pos) { // Pattern -Result Detector::getPatterFileName(Positions pos) const { - return pimpl->Parallel(&Module::getPatterFileName, pos); +Result Detector::getPatternFileName(Positions pos) const { + return pimpl->Parallel(&Module::getPatternFileName, pos); } void Detector::setPattern(const std::string &fname, Positions pos) { diff --git a/slsDetectorSoftware/src/Module.cpp b/slsDetectorSoftware/src/Module.cpp index 5cfa39875..17fe8841b 100644 --- a/slsDetectorSoftware/src/Module.cpp +++ b/slsDetectorSoftware/src/Module.cpp @@ -2668,7 +2668,7 @@ void Module::configureTransceiver() { } // Pattern -std::string Module::getPatterFileName() const { +std::string Module::getPatternFileName() const { char retval[MAX_STR_LENGTH]{}; sendToDetector(F_GET_PATTERN_FILE_NAME, nullptr, retval); return retval; diff --git a/slsDetectorSoftware/src/Module.h b/slsDetectorSoftware/src/Module.h index 1f1f5c2e0..cf4672c93 100644 --- a/slsDetectorSoftware/src/Module.h +++ b/slsDetectorSoftware/src/Module.h @@ -536,7 +536,7 @@ class Module : public virtual slsDetectorDefs { * Pattern * * * * ************************************************/ - std::string getPatterFileName() const; + std::string getPatternFileName() const; void setPattern(const Pattern &pat, const std::string &fname); Pattern getPattern(); void loadDefaultPattern(); diff --git a/slsDetectorSoftware/src/inferAction.cpp b/slsDetectorSoftware/src/inferAction.cpp index 25467d1d2..af2ff6396 100644 --- a/slsDetectorSoftware/src/inferAction.cpp +++ b/slsDetectorSoftware/src/inferAction.cpp @@ -63,6 +63,12 @@ int InferAction::adcclk() { } if (args.size() == 1) { + throw RuntimeError( + "sls_detector is disabled for command: adcclk with number of " + "arguments 1. Use sls_detector_get or sls_detector_put"); + } + + if (args.size() == 2) { return slsDetectorDefs::PUT_ACTION; } @@ -711,6 +717,12 @@ int InferAction::dbitclk() { } if (args.size() == 1) { + throw RuntimeError( + "sls_detector is disabled for command: dbitclk with number of " + "arguments 1. Use sls_detector_get or sls_detector_put"); + } + + if (args.size() == 2) { return slsDetectorDefs::PUT_ACTION; } @@ -2595,6 +2607,12 @@ int InferAction::runclk() { } if (args.size() == 1) { + throw RuntimeError( + "sls_detector is disabled for command: runclk with number of " + "arguments 1. Use sls_detector_get or sls_detector_put"); + } + + if (args.size() == 2) { return slsDetectorDefs::PUT_ACTION; } @@ -3477,6 +3495,10 @@ int InferAction::syncclk() { return slsDetectorDefs::GET_ACTION; } + if (args.size() == 1) { + return slsDetectorDefs::GET_ACTION; + } + else { throw RuntimeError("Could not infer action: Wrong number of arguments"); diff --git a/slsDetectorSoftware/tests/Caller/test-Caller-chiptestboard.cpp b/slsDetectorSoftware/tests/Caller/test-Caller-chiptestboard.cpp index 71c64048f..214c2ffa8 100644 --- a/slsDetectorSoftware/tests/Caller/test-Caller-chiptestboard.cpp +++ b/slsDetectorSoftware/tests/Caller/test-Caller-chiptestboard.cpp @@ -921,23 +921,65 @@ TEST_CASE("adcclk", "[.detectorintegration]") { Caller caller(&det); auto det_type = det.getDetectorType().squash(); - if (det_type == defs::CHIPTESTBOARD) { + if (det_type == defs::CHIPTESTBOARD || + det_type == defs::XILINX_CHIPTESTBOARD) { auto prev_val = det.getADCClock(); + + REQUIRE_NOTHROW(caller.call("adcclk", {"MHZ"}, -1, GET)); + REQUIRE_NOTHROW(caller.call("adcclk", {"mhz"}, -1, GET)); + REQUIRE_NOTHROW(caller.call("adcclk", {"MHz"}, -1, GET)); + REQUIRE_NOTHROW(caller.call("adcclk", {"kHz"}, -1, GET)); + REQUIRE_NOTHROW(caller.call("adcclk", {"Hz"}, -1, GET)); + REQUIRE_NOTHROW(caller.call("adcclk", {}, -1, GET)); + // min + if (det_type == defs::CHIPTESTBOARD) + REQUIRE_THROWS(caller.call("adcclk", {"1", "MHz"}, -1, PUT)); + else + REQUIRE_THROWS(caller.call("adcclk", {"9", "MHz"}, -1, PUT)); + // max + if (det_type == defs::CHIPTESTBOARD) + REQUIRE_THROWS(caller.call("adcclk", {"66", "MHz"}, -1, PUT)); + else + REQUIRE_THROWS(caller.call("adcclk", {"301", "MHz"}, -1, PUT)); + { std::ostringstream oss; - caller.call("adcclk", {"20"}, -1, PUT, oss); - REQUIRE(oss.str() == "adcclk 20\n"); + caller.call("adcclk", {"20MHz"}, -1, PUT, oss); + REQUIRE(oss.str() == "adcclk 20MHz\n"); } { std::ostringstream oss; - caller.call("adcclk", {"10"}, -1, PUT, oss); - REQUIRE(oss.str() == "adcclk 10\n"); + caller.call("adcclk", {"10000000"}, -1, PUT, oss); + REQUIRE(oss.str() == "adcclk 10000000\n"); + } + + { + std::ostringstream oss; + caller.call("adcclk", {}, -1, GET, oss); + REQUIRE(oss.str() == "adcclk 10MHz\n"); + } + { + std::ostringstream oss; + caller.call("adcclk", {"15000", "kHz"}, -1, PUT, oss); + REQUIRE(oss.str() == "adcclk 15000kHz\n"); } { std::ostringstream oss; caller.call("adcclk", {}, -1, GET, oss); - REQUIRE(oss.str() == "adcclk 10\n"); + REQUIRE(oss.str() == "adcclk 15MHz\n"); } + { + std::ostringstream oss; + caller.call("adcclk", {"15.75", "MHz"}, -1, PUT, oss); + REQUIRE(oss.str() == "adcclk 15.75MHz\n"); + } + { + std::ostringstream oss; + caller.call("adcclk", {}, -1, GET, oss); + REQUIRE(oss.str() == "adcclk 15.75MHz\n"); + } + std::cout << "Resetting adc clock to :" << ToString(prev_val) + << std::endl; for (int i = 0; i != det.size(); ++i) { det.setADCClock(prev_val[i], {i}); } @@ -952,25 +994,119 @@ TEST_CASE("runclk", "[.detectorintegration]") { Caller caller(&det); auto det_type = det.getDetectorType().squash(); - if (det_type == defs::CHIPTESTBOARD) { + if (det_type == defs::CHIPTESTBOARD || + det_type == defs::XILINX_CHIPTESTBOARD) { auto prev_val = det.getRUNClock(); + + REQUIRE_NOTHROW(caller.call("runclk", {"MHZ"}, -1, GET)); + REQUIRE_NOTHROW(caller.call("runclk", {"mhz"}, -1, GET)); + REQUIRE_NOTHROW(caller.call("runclk", {"MHz"}, -1, GET)); + REQUIRE_NOTHROW(caller.call("runclk", {"kHz"}, -1, GET)); + REQUIRE_NOTHROW(caller.call("runclk", {"Hz"}, -1, GET)); + REQUIRE_NOTHROW(caller.call("runclk", {}, -1, GET)); + // min + if (det_type == defs::CHIPTESTBOARD) + REQUIRE_THROWS(caller.call("runclk", {"1", "MHz"}, -1, PUT)); + else + REQUIRE_THROWS(caller.call("runclk", {"9", "MHz"}, -1, PUT)); + // max + REQUIRE_THROWS(caller.call("runclk", {"301", "MHz"}, -1, PUT)); + { std::ostringstream oss; - caller.call("runclk", {"20"}, -1, PUT, oss); - REQUIRE(oss.str() == "runclk 20\n"); + caller.call("runclk", {"20MHz"}, -1, PUT, oss); + REQUIRE(oss.str() == "runclk 20MHz\n"); } { std::ostringstream oss; - caller.call("runclk", {"10"}, -1, PUT, oss); - REQUIRE(oss.str() == "runclk 10\n"); + caller.call("runclk", {"10000000"}, -1, PUT, oss); + REQUIRE(oss.str() == "runclk 10000000\n"); + } + + { + std::ostringstream oss; + caller.call("runclk", {}, -1, GET, oss); + REQUIRE(oss.str() == "runclk 10MHz\n"); + } + { + std::ostringstream oss; + caller.call("runclk", {"15000", "kHz"}, -1, PUT, oss); + REQUIRE(oss.str() == "runclk 15000kHz\n"); } { std::ostringstream oss; caller.call("runclk", {}, -1, GET, oss); - REQUIRE(oss.str() == "runclk 10\n"); + REQUIRE(oss.str() == "runclk 15MHz\n"); + } + { + std::ostringstream oss; + caller.call("runclk", {"15.75", "MHz"}, -1, PUT, oss); + REQUIRE(oss.str() == "runclk 15.75MHz\n"); + } + { + std::ostringstream oss; + caller.call("runclk", {}, -1, GET, oss); + REQUIRE(oss.str() == "runclk 15.75MHz\n"); + } + // tolerance + auto prev_exptime = det.getExptime(); + auto prev_period = det.getPeriod(); + auto prev_delay = det.getDelayAfterTrigger(); + { + caller.call("runclk", {"80", "MHz"}, -1, PUT); + { + std::ostringstream oss; + REQUIRE_NOTHROW( + caller.call("exptime", {"10012", "ns"}, -1, PUT)); + REQUIRE_NOTHROW(caller.call("exptime", {"ns"}, -1, GET, oss)); + REQUIRE(oss.str() == "exptime 10013ns\n"); + } + { + std::ostringstream oss; + REQUIRE_NOTHROW( + caller.call("exptime", {"10013", "ns"}, -1, PUT)); + REQUIRE_NOTHROW(caller.call("exptime", {"ns"}, -1, GET, oss)); + REQUIRE(oss.str() == "exptime 10013ns\n"); + } + { + std::ostringstream oss; + REQUIRE_NOTHROW( + caller.call("exptime", {"10019", "ns"}, -1, PUT)); + REQUIRE_NOTHROW(caller.call("exptime", {"ns"}, -1, GET, oss)); + REQUIRE(oss.str() == "exptime 10025ns\n"); + } + { + std::ostringstream oss; + REQUIRE_NOTHROW( + caller.call("period", {"10125", "ns"}, -1, PUT)); + REQUIRE_NOTHROW(caller.call("period", {"ns"}, -1, GET, oss)); + REQUIRE(oss.str() == "period 10125ns\n"); + } + { + std::ostringstream oss; + REQUIRE_NOTHROW( + caller.call("period", {"10124", "ns"}, -1, PUT)); + REQUIRE_NOTHROW(caller.call("period", {"ns"}, -1, GET, oss)); + REQUIRE(oss.str() == "period 10125ns\n"); + } + { + std::ostringstream oss; + REQUIRE_NOTHROW(caller.call("delay", {"10125", "ns"}, -1, PUT)); + REQUIRE_NOTHROW(caller.call("delay", {"ns"}, -1, GET, oss)); + REQUIRE(oss.str() == "delay 10125ns\n"); + } + { + std::ostringstream oss; + REQUIRE_NOTHROW(caller.call("delay", {"10124", "ns"}, -1, PUT)); + REQUIRE_NOTHROW(caller.call("delay", {"ns"}, -1, GET, oss)); + REQUIRE(oss.str() == "delay 10125ns\n"); + } } for (int i = 0; i != det.size(); ++i) { det.setRUNClock(prev_val[i], {i}); + det.setExptime(prev_exptime[i], {i}); + det.setPeriod(prev_period[i], {i}); + det.setDelayAfterTrigger(prev_delay[i], {i}); } } else { // clock index might work @@ -983,6 +1119,11 @@ TEST_CASE("syncclk", "[.detectorintegration]") { Caller caller(&det); auto det_type = det.getDetectorType().squash(); if (det_type == defs::CHIPTESTBOARD) { + REQUIRE_NOTHROW(caller.call("syncclk", {"MHZ"}, -1, GET)); + REQUIRE_NOTHROW(caller.call("syncclk", {"mhz"}, -1, GET)); + REQUIRE_NOTHROW(caller.call("syncclk", {"MHz"}, -1, GET)); + REQUIRE_NOTHROW(caller.call("syncclk", {"kHz"}, -1, GET)); + REQUIRE_NOTHROW(caller.call("syncclk", {"Hz"}, -1, GET)); REQUIRE_NOTHROW(caller.call("syncclk", {}, -1, GET)); } else { // clock index might work @@ -1249,22 +1390,59 @@ TEST_CASE("dbitclk", "[.detectorintegration]") { Caller caller(&det); auto det_type = det.getDetectorType().squash(); - if (det_type == defs::CHIPTESTBOARD) { + if (det_type == defs::CHIPTESTBOARD || + det_type == defs::XILINX_CHIPTESTBOARD) { auto prev_val = det.getDBITClock(); + + REQUIRE_NOTHROW(caller.call("dbitclk", {"MHZ"}, -1, GET)); + REQUIRE_NOTHROW(caller.call("dbitclk", {"mhz"}, -1, GET)); + REQUIRE_NOTHROW(caller.call("dbitclk", {"MHz"}, -1, GET)); + REQUIRE_NOTHROW(caller.call("dbitclk", {"kHz"}, -1, GET)); + REQUIRE_NOTHROW(caller.call("dbitclk", {"Hz"}, -1, GET)); + REQUIRE_NOTHROW(caller.call("dbitclk", {}, -1, GET)); + // min + if (det_type == defs::CHIPTESTBOARD) + REQUIRE_THROWS(caller.call("dbitclk", {"1", "MHz"}, -1, PUT)); + else + REQUIRE_THROWS(caller.call("dbitclk", {"9", "MHz"}, -1, PUT)); + // max + REQUIRE_THROWS(caller.call("dbitclk", {"301", "MHz"}, -1, PUT)); + { std::ostringstream oss; - caller.call("dbitclk", {"20"}, -1, PUT, oss); - REQUIRE(oss.str() == "dbitclk 20\n"); + caller.call("dbitclk", {"20MHz"}, -1, PUT, oss); + REQUIRE(oss.str() == "dbitclk 20MHz\n"); } { std::ostringstream oss; - caller.call("dbitclk", {"10"}, -1, PUT, oss); - REQUIRE(oss.str() == "dbitclk 10\n"); + caller.call("dbitclk", {"10000000"}, -1, PUT, oss); + REQUIRE(oss.str() == "dbitclk 10000000\n"); + } + + { + std::ostringstream oss; + caller.call("dbitclk", {}, -1, GET, oss); + REQUIRE(oss.str() == "dbitclk 10MHz\n"); + } + { + std::ostringstream oss; + caller.call("dbitclk", {"15000", "kHz"}, -1, PUT, oss); + REQUIRE(oss.str() == "dbitclk 15000kHz\n"); } { std::ostringstream oss; caller.call("dbitclk", {}, -1, GET, oss); - REQUIRE(oss.str() == "dbitclk 10\n"); + REQUIRE(oss.str() == "dbitclk 15MHz\n"); + } + { + std::ostringstream oss; + caller.call("dbitclk", {"15.75", "MHz"}, -1, PUT, oss); + REQUIRE(oss.str() == "dbitclk 15.75MHz\n"); + } + { + std::ostringstream oss; + caller.call("dbitclk", {}, -1, GET, oss); + REQUIRE(oss.str() == "dbitclk 15.75MHz\n"); } for (int i = 0; i != det.size(); ++i) { det.setDBITClock(prev_val[i], {i}); diff --git a/slsSupportLib/include/sls/ToString.h b/slsSupportLib/include/sls/ToString.h index 777a98207..7035f9c38 100644 --- a/slsSupportLib/include/sls/ToString.h +++ b/slsSupportLib/include/sls/ToString.h @@ -108,6 +108,12 @@ ToString(From t) { } } +/** Convert frequency with specified output unit */ +std::string ToString(defs::Hz f, defs::FrequencyUnit unit); + +/** Convert frequency automatically selecting the unit */ +std::string ToString(defs::Hz f); + /** Conversion of floating point values, removes trailing zeros*/ template typename std::enable_if::value, std::string>::type @@ -279,7 +285,23 @@ ToString(const T &container, const std::string &unit) { return os.str(); } +/** Container and specified unit, call ToString(value, FrequencyUnit) */ template +typename std::enable_if::value, std::string>::type +ToString(const T &container, defs::FrequencyUnit unit) { + std::ostringstream os; + os << '['; + if (!container.empty()) { + auto it = container.cbegin(); + os << ToString(*it++, unit); + while (it != container.cend()) + os << ", " << ToString(*it++, unit); + } + os << ']'; + return os.str(); +} + +template ::value, int> = 0> T StringTo(const std::string &t, const std::string &unit) { double tval{0}; try { @@ -304,6 +326,33 @@ T StringTo(const std::string &t, const std::string &unit) { } } +template ::value, int> = 0> +T StringTo(const std::string &f, const std::string &unit) { + double fval{0}; + try { + fval = std::stod(f); + } catch (const std::invalid_argument &e) { + throw RuntimeError("Could not convert string to frequency"); + } + auto unitLower = [&] { + std::string result = unit; + std::transform(result.begin(), result.end(), result.begin(), + [](unsigned char c) { return std::tolower(c); }); + return result; + }(); + + if (unitLower == "mhz") { + return T(static_cast(fval * 1e6)); + } else if (unitLower == "khz") { + return T(static_cast(fval * 1e3)); + } else if (unitLower.empty() || unitLower == "hz") { + return T(static_cast(fval)); + } else { + throw RuntimeError( + "Invalid unit in conversion from string to frequency"); + } +} + template T StringTo(const std::string &t) { std::string tmp{t}; auto unit = RemoveUnit(tmp); diff --git a/slsSupportLib/include/sls/TypeTraits.h b/slsSupportLib/include/sls/TypeTraits.h index 1a153e67b..926b2227d 100644 --- a/slsSupportLib/include/sls/TypeTraits.h +++ b/slsSupportLib/include/sls/TypeTraits.h @@ -1,6 +1,8 @@ // SPDX-License-Identifier: LGPL-3.0-or-other // Copyright (C) 2021 Contributors to the SLS Detector Package #pragma once +#include "sls/sls_detector_defs.h" + #include #include @@ -120,4 +122,9 @@ struct has_bool_isValid : std::false_type {}; template struct has_bool_isValid().isValid)>> : std::is_same().isValid), bool> {}; + +template struct is_frequency : std::false_type {}; + +template <> struct is_frequency : std::true_type {}; + } // namespace sls \ No newline at end of file diff --git a/slsSupportLib/include/sls/sls_detector_defs.h b/slsSupportLib/include/sls/sls_detector_defs.h index 54285ba17..283eb2f5e 100644 --- a/slsSupportLib/include/sls/sls_detector_defs.h +++ b/slsSupportLib/include/sls/sls_detector_defs.h @@ -221,6 +221,16 @@ class slsDetectorDefs { std::map addJsonHeader; }; + struct Hz { + int value{0}; + explicit Hz(int v) : value(v){}; + constexpr bool operator==(const Hz &other) const { + return (value == other.value); + } + }; + + enum class FrequencyUnit { Hz, kHz, MHz }; + #endif enum frameDiscardPolicy { NO_DISCARD, @@ -854,7 +864,6 @@ typedef struct { #endif #ifdef __cplusplus - // TODO! discuss this #include //hmm... but currently no way around namespace sls { diff --git a/slsSupportLib/include/sls/versionAPI.h b/slsSupportLib/include/sls/versionAPI.h index 1b1f5ce66..32fba195b 100644 --- a/slsSupportLib/include/sls/versionAPI.h +++ b/slsSupportLib/include/sls/versionAPI.h @@ -3,11 +3,11 @@ /** API versions */ #define APILIB "0.0.0 0x250909" #define APIRECEIVER "0.0.0 0x250822" -#define APICTB "0.0.0 0x260427" +#define APICTB "0.0.0 0x260506" #define APIGOTTHARD2 "0.0.0 0x260427" #define APIMOENCH "0.0.0 0x260424" #define APIEIGER "0.0.0 0x260424" -#define APIXILINXCTB "0.0.0 0x260427" +#define APIXILINXCTB "0.0.0 0x260506" #define APIJUNGFRAU "0.0.0 0x260424" -#define APIMYTHEN3 "0.0.0 0x260427" -#define APIMATTERHORN "0.0.0 0x260212" \ No newline at end of file +#define APIMYTHEN3 "0.0.0 0x260506" +#define APIMATTERHORN "0.0.0 0x260212" diff --git a/slsSupportLib/src/ToString.cpp b/slsSupportLib/src/ToString.cpp index dedb2f165..505b4517f 100644 --- a/slsSupportLib/src/ToString.cpp +++ b/slsSupportLib/src/ToString.cpp @@ -741,6 +741,36 @@ std::string ToString(const defs::collectionMode s) { const std::string &ToString(const std::string &s) { return s; } +std::string ToString(defs::Hz f, defs::FrequencyUnit unit) { + double val = static_cast(f.value); + std::ostringstream os; + switch (unit) { + case defs::FrequencyUnit::Hz: + os << val << "Hz"; + break; + case defs::FrequencyUnit::kHz: + os << val / (static_cast(1e3)) << "kHz"; + break; + case defs::FrequencyUnit::MHz: + os << val / (static_cast(1e6)) << "MHz"; + break; + default: + throw std::runtime_error("Unknown frequency unit"); + } + return os.str(); +} + +std::string ToString(defs::Hz f) { + int val = f.value; + if (val < 1e3) { + return ToString(f, defs::FrequencyUnit::Hz); + } else if (val < 1e6) { + return ToString(f, defs::FrequencyUnit::kHz); + } else { + return ToString(f, defs::FrequencyUnit::MHz); + } +} + template <> defs::detectorType StringTo(const std::string &s) { if (s == "Eiger") return defs::EIGER; diff --git a/slsSupportLib/tests/test-ToString.cpp b/slsSupportLib/tests/test-ToString.cpp index 3d35004e8..0c35bdfc0 100644 --- a/slsSupportLib/tests/test-ToString.cpp +++ b/slsSupportLib/tests/test-ToString.cpp @@ -76,6 +76,15 @@ TEST_CASE("conversion from duration to string", "[support]") { REQUIRE(ToString(us(-100)) == "-100us"); } +TEST_CASE("conversion from frequency to string", "[support]") { + REQUIRE(ToString(defs::Hz(150)) == "150Hz"); + REQUIRE(ToString(defs::Hz(1500)) == "1.5kHz"); + REQUIRE(ToString(defs::Hz(1500000)) == "1.5MHz"); + REQUIRE(ToString(defs::Hz(150), defs::FrequencyUnit::Hz) == "150Hz"); + REQUIRE(ToString(defs::Hz(150), defs::FrequencyUnit::kHz) == "0.15kHz"); + REQUIRE(ToString(defs::Hz(150), defs::FrequencyUnit::MHz) == "0.00015MHz"); +} + TEST_CASE("Convert vector of time", "[support]") { std::vector vec{ns(150), us(10), ns(600)}; REQUIRE(ToString(vec) == "[150ns, 10us, 600ns]"); @@ -155,6 +164,15 @@ TEST_CASE("string to std::chrono::duration", "[support]") { REQUIRE_THROWS(StringTo("asvn")); } +TEST_CASE("string to frequency", "[support]") { + REQUIRE(StringTo("150") == defs::Hz(150)); + REQUIRE(StringTo("150Hz") == defs::Hz(150)); + REQUIRE(StringTo("1.5kHz") == defs::Hz(1500)); + REQUIRE(StringTo("1.5MHz") == defs::Hz(1500000)); + REQUIRE_THROWS(StringTo("5xs")); + REQUIRE_THROWS(StringTo("asvn")); +} + TEST_CASE("string to detectorType") { using dt = slsDetectorDefs::detectorType; REQUIRE(StringTo
("Eiger") == dt::EIGER);