Merge branch 'developer' into add-rx-header

This commit is contained in:
2026-05-11 09:01:13 +02:00
committed by GitHub
co-authored by GitHub
94 changed files with 4020 additions and 1011 deletions
@@ -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}}
@@ -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}}
+1 -1
View File
@@ -54,7 +54,7 @@ jobs:
- name: Install System Packages
uses: awalsh128/cache-apt-pkgs-action@latest
with:
packages: libhdf5-dev doxygen
packages: libhdf5-dev doxygen libfmt-dev
version: 1.0
- name: Setup Python
+1 -1
View File
@@ -23,7 +23,7 @@ jobs:
- uses: awalsh128/cache-apt-pkgs-action@latest
with:
packages: libhdf5-dev qtbase5-dev qt5-qmake libqt5svg5-dev libpng-dev libtiff-dev
packages: libhdf5-dev qtbase5-dev qt5-qmake libqt5svg5-dev libpng-dev libtiff-dev libfmt-dev
version: 1.0
- name: Configure CMake
+2 -2
View File
@@ -18,11 +18,11 @@ 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:
packages: libhdf5-dev
packages: libhdf5-dev libfmt-dev
version: 1.0
- name: Configure CMake
+51 -7
View File
@@ -32,6 +32,7 @@ if(NOT CMAKE_USE_PTHREADS_INIT)
message(FATAL_ERROR "A POSIX threads (pthread) implementation is required, but was not found.")
endif()
set(SLS_LOG_MAX_REPORTING_LEVEL "sls::TLogLevel::logINFO" CACHE STRING "Set the maximum logging level for the project")
option(SLS_USE_SYSTEM_ZMQ "Use system installed libzmq" OFF)
@@ -39,6 +40,7 @@ option(SLS_USE_SYSTEM_ZMQ "Use system installed libzmq" OFF)
include(FetchContent)
option(SLS_FETCH_ZMQ_FROM_GITHUB "Fetch zmq from github" OFF)
option(SLS_FETCH_PYBIND11_FROM_GITHUB "Fetch pybind11 from github" OFF)
option(SLS_FETCH_FMT_FROM_GITHUB "Fetch fmt from github" OFF)
# Allow FetchContent_Populate to be called with a single argument
# otherwise deprecated warning is issued
@@ -187,6 +189,40 @@ if (CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR)
set(SLS_MASTER_PROJECT ON)
endif()
if (SLS_FETCH_FMT_FROM_GITHUB)
set(FMT_TEST OFF CACHE INTERNAL "disabling fmt tests")
FetchContent_Declare(
fmt
GIT_REPOSITORY https://github.com/fmtlib/fmt.git
GIT_TAG 12.1.0
GIT_PROGRESS TRUE
USES_TERMINAL_DOWNLOAD TRUE
)
set(FMT_INSTALL ON CACHE BOOL "")
FetchContent_MakeAvailable(fmt)
set_property(TARGET fmt PROPERTY POSITION_INDEPENDENT_CODE ON)
else()
# downloaded from https://github.com/fmtlib/fmt/releases/tag/12.1.0
set(FMT_TEST OFF CACHE INTERNAL "disabling fmt tests")
FetchContent_Declare(
fmt
URL ${CMAKE_CURRENT_SOURCE_DIR}/libs/fmt/fmt-12.1.0.tar.gz
# Compute hash: md5sum fmt-12.1.0.tar.gz
URL_HASH MD5=92eb6f492e4838e5f024ce5207beafc7)
FetchContent_MakeAvailable(fmt)
set_property(TARGET fmt PROPERTY POSITION_INDEPENDENT_CODE ON)
endif()
# Export fmt
if(SLS_MASTER_PROJECT)
install(TARGETS fmt
EXPORT ${TARGETS_EXPORT_NAME}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
)
endif()
option(SLS_USE_HDF5 "HDF5 File format" OFF)
@@ -194,6 +230,7 @@ option(SLS_BUILD_SHARED_LIBRARIES "Build shared libaries" OFF)
option(SLS_USE_TEXTCLIENT "Text Client" ON)
option(SLS_USE_DETECTOR "Detector libs" ON)
option(SLS_USE_RECEIVER "Receiver" ON)
option(SLS_USE_SERVER "Server" ON)
option(SLS_USE_RECEIVER_BINARIES "Receiver binaries" ON)
option(SLS_USE_GUI "GUI" OFF)
option(SLS_USE_SIMULATOR "Simulator" OFF)
@@ -208,6 +245,7 @@ option(SLS_TUNE_LOCAL "tune to local machine" OFF)
option(SLS_DEVEL_HEADERS "install headers for devel" OFF)
option(SLS_USE_MOENCH "compile zmq and post processing for Moench" OFF)
option(SLS_USE_JUNGFRAU "compile post processing for Jungfrau" OFF)
option(SLS_USE_MATTERHORN "compile matterhorn server" OFF)
option(SLS_INSTALL_VERSIONED_BINARIES "Add version number to binaries on install" OFF) #Needed for multi version RPM
#Convenience option to switch off defaults when building Moench binaries only
@@ -282,18 +320,15 @@ if(SLS_EXT_BUILD)
endif()
# slsProjectOptions and slsProjectWarnings are used
# to control options for the libraries
if(NOT TARGET slsProjectOptions)
add_library(slsProjectOptions INTERFACE)
target_compile_features(slsProjectOptions INTERFACE cxx_std_17)
target_compile_features(slsProjectOptions INTERFACE cxx_std_17)
target_compile_definitions(slsProjectOptions
INTERFACE LOG_MAX_REPORTING_LEVEL=${SLS_LOG_MAX_REPORTING_LEVEL})
endif()
set(LOG_MAX_REPORTING_LEVEL sls::logINFO CACHE STRING "set logging level")
target_compile_definitions(slsProjectOptions
INTERFACE LOG_MAX_REPORTING_LEVEL=${LOG_MAX_REPORTING_LEVEL}
)
if (NOT TARGET slsProjectWarnings)
add_library(slsProjectWarnings INTERFACE)
@@ -393,7 +428,12 @@ endif()
if (SLS_USE_DETECTOR OR SLS_USE_TEXTCLIENT)
add_subdirectory(slsDetectorSoftware)
endif ()
endif()
# TODO refactor with simulators
if (SLS_USE_SERVER)
add_subdirectory(slsDetectorServers/slsDetectorServer_cpp)
endif()
if (SLS_USE_RECEIVER)
add_subdirectory(slsReceiverSoftware)
@@ -404,6 +444,10 @@ if (SLS_USE_GUI)
add_subdirectory(slsDetectorGui)
endif (SLS_USE_GUI)
if (SLS_USE_MATTERHORN)
add_subdirectory(slsDetectorServers/matterhornServer)
endif()
if (SLS_USE_SIMULATOR)
add_subdirectory(slsDetectorServers)
endif (SLS_USE_SIMULATOR)
+35 -24
View File
@@ -83,51 +83,62 @@ To use the basic building blocks, meaning sls_detector_get/put and the shared li
> **Note:** For v9.x.x of slsDetectorPackage and older, C++11 compatible compiler.
#### Python bindings
* Python >= 3.8
Additionally the core requires the following dependencies:
* pybind11 2.13.6 (packaged in libs)
* fmt 12.1.0 (packaged in libs) (since version 11.0.0)
* ZeroMQ 4.3.4 (packaged in libs)
* rapidjson (packaged in libs)
> **Note:** Refer [pybind11 notes](#4-pybind-and-zeromq).
#### ZeroMQ
* Zeromq 4.3.4 (packaged in libs)
> **Note:** Both fmt, ZeroMQ and rapidjson are bundled in libs. One does not need to pre-install them on the system. Alternatively, one can fetch fmt and ZeroMQ from GitHub by passing the cmake options ``-DSLS_FETCH_FMT_FROM_GITHUB=ON`` and ``-DSLS_FETCH_ZEROMQ_FROM_GITHUB=ON`` respectively.
> **Note:** Refer [zeromq notes](#4-pybind-and-zeromq).
#### GUI
#### Dependencies to build Python module
* Qt 5.9
To build the python module the following dependencies are needed:
* Qwt 6.1.5 (packaged in libs)
* Python >= 3.8
* pybind11 2.13.6 (packaged in libs)
> **Note:** pybind11 is bundled in libs. One does not need to pre-install it on the system. Alternatively, one can fetch pybind11 from GitHub by passing the cmake option ``-DSLS_FETCH_PYBIND11_FROM_GITHUB=ON``.
#### Moench executables
> **Note:** Refer [pybind11 notes](#4-pybind-and-zeromq).
* libtiff
#### Documentation
#### Dependencies to build documentation
The documentation is built with
* Doxygen (to extract C++ classes etc.)
To build this documentation that you are reading now the following dependencies are needed:
* Breathe (Sphinx plugin to handle doxygen xml)
* Doxygen (to extract C++ classes etc.)
* Breathe (Sphinx plugin to handle doxygen xml)
* Sphinx with sphinx_rtd_theme
* Sphinx with sphinx_rtd_theme
#### Dependencies to build GUI
#### Packaged in libs/
To build the GUI the following dependencies are needed:
* catch2 (unit testing)
* Qt 5.9
* Qwt 6.1.5 (packaged in libs)
* rapidjson (streaming from receiver)
> **Note:** Qwt is bundled in libs. One does not need to pre-install it on the system.
* pybind11 (python bindings)
* qwt (gui plotting)
#### Dependencies to build Moench and Jungfrau executables
* libzmq (streaming to/from receiver)
To build the Moench and Jungfrau executables for preprocessing and calibration the following dependencies are needed:
* libtiff
#### Dependencies to build Tests
To build the tests the following dependencies are needed:
* Catch2 3.4.0 (packaged in libs)
> **Note:** Catch2 is bundled in libs. One does not need to pre-install it on the system.
### 3.2. Download Source Code from github
```
+1
View File
@@ -30,6 +30,7 @@ requirements:
- zlib
- expat
- zeromq
- fmt
run:
- libstdcxx-ng
+10 -42
View File
@@ -101,7 +101,7 @@ To run only tests requiring virtual detectors use the following command:
#in build
python -m pytest -m detectorintegration ../python/tests/
There is a helper test fixture in ``slsDetectorSoftware/python/tests/conftest.py`` called ``test_with_simulators`` that sets up virtual detectors and yields the test for all detectors. The set up is done for every test automatically.
There is a helper test fixture in ``slsDetectorSoftware/python/tests/conftest.py`` called ``session_simulator`` that sets up virtual detectors and yields the test for all detectors. The set up is done for every test automatically. Note that the fixture persist over the entire session e.g. the fixture is setup one detector at a time and runs all tests using this fixture before cleaning up and moving on to the next detector. It saves time if the setup and cleanup is expensive.
Example usage:
@@ -110,10 +110,13 @@ Example usage:
import pytest
@pytest.mark.detectorintegration
def test_example_with_simulator(test_with_simulators):
def test_example_with_simulator(session_simulator):
# your test code here
If you want to run the test only for a specific test use the parametrized test fixture:
.. Note::
As the detector is set up only once makes sure to not change the state of the detector in a way that affects other tests. If you want to change the state of the detector make sure to reset it at the end of your test.
If you want to run the test only for a specific detector use the parametrized test fixture:
Example usage:
@@ -122,45 +125,10 @@ Example usage:
import pytest
@pytest.mark.detectorintegration
@pytest.mark.parametrize("setup_parameters", [(["<my_detector>"], <num_modules>)], indirect=True)
def test_example_with_specific_simulators(test_with_simulators, setup_parameters):
@pytest.mark.parametrize("session_simulator", [("<my_detector>", <num_interfaces>, <num_modules>), ("<another_detector>", <num_interfaces>, <num_modules>)], indirect=True)
def test_example_with_specific_simulators(session_simulator):
# your test code here
.. Note::
The parametrized test fixture is setup per file and not for the entire session.
There is another helper test fixture in ``slsDetectorSoftware/python/tests/conftest.py`` called ``session_simulator`` that sets up virtual detectors and yields the test for all detectors. The difference with the previous fixture ``test_with_simulators`` is that this fixture will set up one detector at a time and run all the tests using this fixture before cleaning up and moving on to the next detector. It saves time if the setup and cleanup is expensive.
Example usage:
.. code-block:: python
import pytest
@pytest.mark.detectorintegration
def test_define_reg(session_simulator, request):
""" Test setting define_reg for ctb and xilinx_ctb."""
det_type, num_interfaces, num_mods, d = session_simulator
assert d is not None
from slsdet import RegisterAddress
if det_type in ['ctb', 'xilinx_ctb']:
# your test code here
For more specific parameters, you can parametrize the fixture like below:
.. code-block:: python
import pytest
@pytest.mark.detectorintegration
@pytest.mark.parametrize(
"session_simulator",
[
("ctb", 1, 1),
("xilinx_ctb", 1, 1),
],
indirect=True,
)
def test_define_reg(session_simulator):
det_type, num_interfaces, num_mods, d = session_simulator
# your test code here
+58 -37
View File
@@ -16,61 +16,82 @@ the shared libraries these are needed:
* CMake >= 3.14
* C++17 compatible compiler. (We test with gcc and clang)
.. note ::
.. note::
For v9.x.x of slsDetectorPackage and older, C++11 compatible compiler.
-----------------------
Python bindings
-----------------------
Additionally the core requires the following dependencies:
* Python >= 3.8
* pybind11 2.13.6 (packaged in libs)
* fmt 12.1.0 (packaged in libs)
* ZeroMQ 4.3.4 (packaged in libs)
* rapidjson (packaged in libs)
.. note ::
.. note::
Refer :ref:`pybind11 notes. <pybind for different slsDetectorPackage versions>`
Both fmt, ZeroMQ and rapidjson are bundled in libs. One does not need to pre-install them on the system. Alternatively, one can fetch fmt and ZeroMQ from GitHub by passing the cmake options ``-DSLS_FETCH_FMT_FROM_GITHUB=ON`` and ``-DSLS_FETCH_ZEROMQ_FROM_GITHUB=ON`` respectively.
-----------------------
ZeroMQ
-----------------------
* Zeromq 4.3.4 (packaged in libs)
.. note ::
.. note::
Refer :ref:`zeromq notes. <zeromq for different slsDetectorPackage versions>`
-----------------------
GUI
-----------------------
------------------------------------
Dependencies to build Python module
------------------------------------
To build the python module the following dependencies are needed:
* Python >= 3.8
* pybind11 2.13.6 (packaged in libs)
.. note::
pybind11 is bundled in libs. One does not need to pre-install it on the system. Alternatively, one can fetch pybind11 from GitHub by passing the cmake option ``-DSLS_FETCH_PYBIND11_FROM_GITHUB=ON``.
.. note::
Refer :ref:`pybind11 notes. <pybind for different slsDetectorPackage versions>`
-------------------------------
Dependencies to build documentation
-------------------------------
To build this documentation that you are reading now the following dependencies are needed:
* Doxygen (to extract C++ classes etc.)
* Breathe (Sphinx plugin to handle doxygen xml)
* Sphinx with sphinx_rtd_theme
-------------------------
Dependencies to build GUI
-------------------------
To build the GUI the following dependencies are needed:
* Qt 5.9
* Qwt 6.1.5 (packaged in libs)
-----------------------
Moench executables
-----------------------
.. note::
Qwt is bundled in libs. One does not need to pre-install it on the system.
------------------------------------------------------
Dependencies to build Moench and Jungfrau executables
-----------------------------------------------------
To build the Moench and Jungfrau executables for preprocessing and calibration the following dependencies are needed:
* libtiff
-----------------------
Documentation
-----------------------
--------------------------------------------------
Dependencies to build Tests
--------------------------------------------------
The documentation that you are reading now is built with
To build the tests the following dependencies are needed:
* Doxygen (to extract C++ classes etc.)
* Breathe (Sphinx plugin to handle doxygen xml)
* Sphinx with sphinx_rtd_theme
* Catch2 3.4.0 (packaged in libs)
-----------------------
Packaged in libs/
-----------------------
* catch2 (unit testing)
* rapidjson (streaming from receiver)
* pybind11 (python bindings)
* qwt (gui plotting)
* libzmq (streaming to/from receiver)
.. note::
Catch2 is bundled in libs. One does not need to pre-install it on the system.
+113
View File
@@ -0,0 +1,113 @@
import pandas as pd
import argparse
def Ip_core_name_to_enum_type(ip_core_name : str) -> str:
"""Convert IP core name to enum type IPCore."""
if pd.isna(ip_core_name):
return "IPCore::UNKNOWN"
return f"IPCore::{ip_core_name.upper()}"
def create_bitmask_and_offset(from_bit : int, to_bit : int) -> tuple[int, int]:
"""Create a bitmask for a register field given the from_bit and to_bit."""
if from_bit < 0 or to_bit < 0 or from_bit > to_bit or from_bit >= 32 or to_bit >= 32:
raise ValueError(f"Invalid bit range: from_bit={from_bit}, to_bit={to_bit}")
offset = from_bit
num_bits = to_bit - from_bit + 1
adress_space = 0xFFFFFFFF # Assuming a 32-bit address space for the bitmask
mask = (adress_space >> (32 - num_bits))
return mask, offset # to get value of field: (register_value >> offset) & mask, to set value of field: register_value = (register_value & ~(mask << offset)) | ((field_value & mask) << offset)
def argument_parser():
parser = argparse.ArgumentParser(description="Generate register definitions from a CSV file.")
parser.add_argument("--csv_file", required=True, help="Path to the CSV file containing register definitions.")
parser.add_argument("--output_header_file", required=True, help="Path to the output header file to write the register definitions to.")
parser.add_argument(
"--overwrite",
action="store_true",
help="Overwrite the output file instead of appending.",
)
return parser.parse_args()
# TODO: should be configurable
header = r"""
// clang-format off
#include "RegisterHelperStructs.hpp"
namespace sls {
/// @brief Enum for IP cores, value are adresses
enum class IPCore : uint32_t {
MH_RO_SM_AXI = 0, // dummy adresses for now
FHDR_AXI = 1,
AURORA_STATUS = 2,
AURORA_STATUS2 = 3,
PACKETIZERREG = 4,
UNKNOWN = 5
};
"""
postpend = r"""
} // namespace sls
// clang-format on
"""
def main():
args = argument_parser()
registers_list = pd.read_csv(args.csv_file)
registers = registers_list.drop_duplicates(subset=["Reg_name", "Address"])
file_mode = "w" if args.overwrite else "a"
header_file = open(args.output_header_file, file_mode)
if args.overwrite:
header_file.write(header)
header_file.write("\n\n")
header_file.write("// Register definitions")
header_file.write("\n")
for index, row in registers.iterrows():
local_address_offset_in_bytes = row["Address"]
register_name = row["Reg_name"]
ip_core_name = row["Interface"]
define_register_string = (
f"constexpr Register {register_name}{{"
f"{Ip_core_name_to_enum_type(ip_core_name)}, {hex(int(local_address_offset_in_bytes, 16))}}};"
)
header_file.write(f"{define_register_string}\n")
header_file.write("\n")
header_file.write("\n")
header_file.write("\n")
header_file.write("// Register fields")
header_file.write("\n")
for index, row in registers_list.iterrows():
register_name = row["Reg_name"]
field_name = row["Name"]
from_bit = row["From_bit"]
to_bit = row["To_bit"]
mask, offset = create_bitmask_and_offset(from_bit, to_bit)
define_registerfield_string = (
f"constexpr RegisterField {field_name}{{\n"
f" {register_name}, {offset}, {hex(mask)}}};"
)
header_file.write(f"{define_registerfield_string}\n")
header_file.write("\n")
header_file.write(postpend) # TODO: have to take care xof it manually when in append mode - ugly
header_file.close()
if __name__ == "__main__":
main()
Binary file not shown.
+42 -40
View File
@@ -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()
+377 -238
View File
@@ -36,7 +36,7 @@
</property>
<layout class="QGridLayout" name="gridLayout_19">
<item row="1" column="5">
<widget class="QSpinBox" name="spinBoxRunF">
<widget class="QDoubleSpinBox" name="spinBoxRunF">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
@@ -45,13 +45,13 @@
</property>
<property name="minimumSize">
<size>
<width>125</width>
<width>120</width>
<height>31</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>125</width>
<width>120</width>
<height>31</height>
</size>
</property>
@@ -61,18 +61,17 @@
<property name="buttonSymbols">
<enum>QAbstractSpinBox::UpDownArrows</enum>
</property>
<property name="decimals">
<number>3</number>
</property>
<property name="maximum">
<number>1000</number>
<double>999999999.000000000000000</double>
</property>
<property name="singleStep">
<double>1.000000000000000</double>
</property>
<property name="value">
<number>0</number>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_398">
<property name="text">
<string>Read Out Mode: </string>
<double>0.000000000000000</double>
</property>
</widget>
</item>
@@ -117,13 +116,67 @@
</item>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_398">
<property name="text">
<string>Read Out Mode: </string>
</property>
</widget>
</item>
<item row="1" column="4">
<widget class="QLabel" name="labelRunF">
<property name="text">
<string>Run Clock Frequency (MHz):</string>
<string>Run Clock Frequency:</string>
</property>
</widget>
</item>
<item row="1" column="6">
<widget class="QComboBox" name="comboBoxRunF">
<property name="minimumSize">
<size>
<width>60</width>
<height>31</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>60</width>
<height>16777215</height>
</size>
</property>
<item>
<property name="text">
<string>MHz</string>
</property>
</item>
<item>
<property name="text">
<string>kHz</string>
</property>
</item>
<item>
<property name="text">
<string>Hz</string>
</property>
</item>
</widget>
</item>
<item row="1" column="3">
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Expanding</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>10</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<widget class="QFrame" name="frame_13">
@@ -152,13 +205,13 @@
</property>
<property name="minimumSize">
<size>
<width>125</width>
<width>185</width>
<height>32</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>125</width>
<width>185</width>
<height>32</height>
</size>
</property>
@@ -210,6 +263,12 @@
<height>201</height>
</rect>
</property>
<property name="minimumSize">
<size>
<width>190</width>
<height>0</height>
</size>
</property>
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
</property>
@@ -217,16 +276,128 @@
<enum>QFrame::Sunken</enum>
</property>
<layout class="QGridLayout" name="gridLayout_6">
<item row="2" column="3">
<widget class="QLabel" name="labelDBITF">
<property name="minimumSize">
<item row="4" column="0">
<widget class="QLabel" name="labelADCPipeline">
<property name="text">
<string>ADC Pipeline:</string>
</property>
</widget>
</item>
<item row="2" column="4">
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Expanding</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>200</width>
<height>0</height>
<width>10</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="3" column="5">
<widget class="QLabel" name="labelDBITPhase">
<property name="text">
<string>DBIT Clock Frequency (MHz):</string>
<string>DBIT Clock Phase (a.u.):</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QDoubleSpinBox" name="spinBoxADCF">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>120</width>
<height>31</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>120</width>
<height>31</height>
</size>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="decimals">
<number>3</number>
</property>
<property name="maximum">
<double>999999999.000000000000000</double>
</property>
<property name="singleStep">
<double>1.000000000000000</double>
</property>
<property name="value">
<double>0.000000000000000</double>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="labelADCPhase">
<property name="text">
<string>ADC Clock Phase (a.u.):</string>
</property>
</widget>
</item>
<item row="4" column="5">
<widget class="QLabel" name="labelDBITPipeline">
<property name="text">
<string>DBIT Pipeline:</string>
</property>
</widget>
</item>
<item row="0" column="5">
<widget class="QLabel" name="labelDigital">
<property name="text">
<string>Digital Samples:</string>
</property>
</widget>
</item>
<item row="2" column="6">
<widget class="QDoubleSpinBox" name="spinBoxDBITF">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>120</width>
<height>31</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>120</width>
<height>31</height>
</size>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="decimals">
<number>3</number>
</property>
<property name="maximum">
<double>999999999.000000000000000</double>
</property>
<property name="singleStep">
<double>1.000000000000000</double>
</property>
<property name="value">
<double>0.000000000000000</double>
</property>
</widget>
</item>
@@ -245,213 +416,7 @@
</size>
</property>
<property name="text">
<string>ADC Clock Frequency (MHz):</string>
</property>
</widget>
</item>
<item row="3" column="4">
<widget class="QSpinBox" name="spinBoxDBITPhase">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>125</width>
<height>31</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>125</width>
<height>31</height>
</size>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="maximum">
<number>9999</number>
</property>
</widget>
</item>
<item row="4" column="3">
<widget class="QLabel" name="labelDBITPipeline">
<property name="text">
<string>DBIT Pipeline:</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QSpinBox" name="spinBoxADCF">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>125</width>
<height>31</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>125</width>
<height>31</height>
</size>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="maximum">
<number>1000</number>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QSpinBox" name="spinBoxADCPipeline">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>125</width>
<height>31</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>125</width>
<height>31</height>
</size>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="labelADCPipeline">
<property name="text">
<string>ADC Pipeline:</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="labelADCPhase">
<property name="text">
<string>ADC Clock Phase (a.u.):</string>
</property>
</widget>
</item>
<item row="3" column="3">
<widget class="QLabel" name="labelDBITPhase">
<property name="text">
<string>DBIT Clock Phase (a.u.):</string>
</property>
</widget>
</item>
<item row="2" column="2">
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Expanding</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>10</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="2" column="4">
<widget class="QSpinBox" name="spinBoxDBITF">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>125</width>
<height>31</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>125</width>
<height>31</height>
</size>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="maximum">
<number>1000</number>
</property>
</widget>
</item>
<item row="4" column="4">
<widget class="QSpinBox" name="spinBoxDBITPipeline">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>125</width>
<height>31</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>125</width>
<height>31</height>
</size>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QSpinBox" name="spinBoxADCPhase">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>125</width>
<height>31</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>125</width>
<height>31</height>
</size>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="maximum">
<number>9999</number>
<string>ADC Clock Frequency:</string>
</property>
</widget>
</item>
@@ -462,7 +427,51 @@
</property>
</widget>
</item>
<item row="0" column="1">
<item row="2" column="5">
<widget class="QLabel" name="labelDBITF">
<property name="minimumSize">
<size>
<width>200</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>DBIT Clock Frequency:</string>
</property>
</widget>
</item>
<item row="2" column="2">
<widget class="QComboBox" name="comboBoxADCF">
<property name="minimumSize">
<size>
<width>60</width>
<height>31</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>60</width>
<height>16777215</height>
</size>
</property>
<item>
<property name="text">
<string>MHz</string>
</property>
</item>
<item>
<property name="text">
<string>kHz</string>
</property>
</item>
<item>
<property name="text">
<string>Hz</string>
</property>
</item>
</widget>
</item>
<item row="0" column="1" colspan="2">
<widget class="QSpinBox" name="spinBoxAnalog">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
@@ -472,13 +481,13 @@
</property>
<property name="minimumSize">
<size>
<width>125</width>
<width>185</width>
<height>32</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>125</width>
<width>185</width>
<height>32</height>
</size>
</property>
@@ -493,14 +502,60 @@
</property>
</widget>
</item>
<item row="0" column="3">
<widget class="QLabel" name="labelDigital">
<property name="text">
<string>Digital Samples:</string>
<item row="3" column="1" colspan="2">
<widget class="QSpinBox" name="spinBoxADCPhase">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>185</width>
<height>31</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>185</width>
<height>31</height>
</size>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="maximum">
<number>9999</number>
</property>
</widget>
</item>
<item row="0" column="4">
<item row="4" column="1" colspan="2">
<widget class="QSpinBox" name="spinBoxADCPipeline">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>185</width>
<height>31</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>185</width>
<height>31</height>
</size>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="0" column="6" colspan="2">
<widget class="QSpinBox" name="spinBoxDigital">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
@@ -510,13 +565,13 @@
</property>
<property name="minimumSize">
<size>
<width>125</width>
<width>185</width>
<height>32</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>125</width>
<width>185</width>
<height>32</height>
</size>
</property>
@@ -534,6 +589,90 @@
</property>
</widget>
</item>
<item row="3" column="6" colspan="2">
<widget class="QSpinBox" name="spinBoxDBITPhase">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>185</width>
<height>31</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>185</width>
<height>31</height>
</size>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="maximum">
<number>9999</number>
</property>
</widget>
</item>
<item row="4" column="6" colspan="2">
<widget class="QSpinBox" name="spinBoxDBITPipeline">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>185</width>
<height>31</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>185</width>
<height>31</height>
</size>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="2" column="7">
<widget class="QComboBox" name="comboBoxDBITF">
<property name="minimumSize">
<size>
<width>60</width>
<height>31</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>60</width>
<height>16777215</height>
</size>
</property>
<item>
<property name="text">
<string>MHz</string>
</property>
</item>
<item>
<property name="text">
<string>kHz</string>
</property>
</item>
<item>
<property name="text">
<string>Hz</string>
</property>
</item>
</widget>
</item>
</layout>
</widget>
<widget class="QFrame" name="frame_11">
+1
View File
@@ -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
+3
View File
@@ -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():
+32 -13
View File
@@ -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. """
+15 -15
View File
@@ -1529,23 +1529,31 @@ void init_det(py::module &m) {
Detector::setNumberOfAnalogSamples,
py::arg(), py::arg() = Positions{});
CppDetectorApi.def("getADCClock",
(Result<int>(Detector::*)(sls::Positions) const) &
(Result<defs::Hz>(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<int>(Detector::*)(sls::Positions) const) &
(Result<defs::Hz>(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<defs::Hz>(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<int>(Detector::*)(sls::Positions) const) &
(Result<defs::Hz>(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<int>(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<int>(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<std::string>(Detector::*)(sls::Positions) const) &
Detector::getPatterFileName,
Detector::getPatternFileName,
py::arg() = Positions{});
CppDetectorApi.def(
"setPattern",
+55
View File
@@ -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 <cmath>
#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_<slsDetectorDefs::Hz> Hz(m, "Hz");
Hz.def(py::init<int>());
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<int>(std::round(v * kHz)));
});
m.def("MHz", [](double v) {
return slsDetectorDefs::Hz(static_cast<int>(std::round(v * MHz)));
});
}
+2
View File
@@ -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");
+37 -78
View File
@@ -58,39 +58,56 @@ DEFAULT_SIMULATOR_CONFIGS = [
SIMULATOR_IDS = [f"{det_type}_{num_interface}if_{num_mod}mod" for det_type, num_interface, num_mod in DEFAULT_SIMULATOR_CONFIGS]
'''
for more specific parameters
@pytest.mark.detectorintegration
@pytest.mark.parametrize(
"session_simulator",
[
("ctb", 1, 1),
("xilinx_ctb", 1, 1),
],
indirect=True,
)
def test_define_reg(session_simulator):
det_type, num_interfaces, num_mods, d = session_simulator
'''
@pytest.fixture(scope="session")
def session_simulator(request):
"""
Fixture to start the detector server once and clean up at the end.
Expects request.param = (det_type, num_interfaces, num_mods)
"""
det_type, num_interfaces, num_mods = request.param
fp = sys.stdout
try:
det_type, num_interfaces, num_mods = request.param
fp = sys.stdout
# set up: once per server
Log(LogLevel.INFOBLUE,
f'---- {det_type} | interfaces={num_interfaces} | modules={num_mods} ----', fp)
# set up: once per server
Log(LogLevel.INFOBLUE,
f'---- {det_type} | interfaces={num_interfaces} | modules={num_mods} ----', fp)
cleanup(fp)
startDetectorVirtualServer(det_type, num_mods, fp, True)
startReceiver(num_mods, fp, True)
cleanup(fp)
startDetectorVirtualServer(det_type, num_mods, fp, True, True)
startReceiver(num_mods, fp, True)
Log(LogLevel.INFOBLUE, f'Waiting for server to start up and connect', fp)
d = loadConfig(
name=det_type,
log_file_fp=fp,
num_mods=num_mods,
num_frames=1,
num_interfaces=num_interfaces,
)
Log(LogLevel.INFOBLUE, f'Waiting for server to start up and connect', fp)
d = loadConfig(
name=det_type,
log_file_fp=fp,
num_mods=num_mods,
num_frames=1,
num_interfaces=num_interfaces,
)
loadBasicSettings(name=det_type, d=d, fp=fp)
loadBasicSettings(name=det_type, d=d, fp=fp)
yield det_type, num_interfaces, num_mods, d
cleanup(fp)
yield det_type, num_interfaces, num_mods, d
cleanup(fp)
except Exception as e:
Log(LogLevel.ERROR, f'Tests Failed.', fp)
cleanup(fp)
def pytest_generate_tests(metafunc):
if "session_simulator" not in metafunc.fixturenames:
@@ -110,62 +127,4 @@ def pytest_generate_tests(metafunc):
indirect=True
)
'''
for more specific parameters
@pytest.mark.detectorintegration
@pytest.mark.parametrize(
"session_simulator",
[
("ctb", 1, 1),
("xilinx_ctb", 1, 1),
],
indirect=True,
)
def test_define_reg(session_simulator):
det_type, num_interfaces, num_mods, d = session_simulator
'''
#helper fixture for servers
@pytest.fixture(scope='module')
def setup_parameters(request): # only setup once per module if same parameters used for the scopes
try:
servers, nmods = request.param # comes from @pytest.mark.parametrize(..., indirect=True)
return servers, nmods
except AttributeError:
# fallback default if the test did not parametrize
return (['eiger', 'jungfrau', 'mythen3', 'gotthard2', 'ctb', 'moench', 'xilinx_ctb'], 2)
@pytest.fixture(scope='module')
def test_with_simulators(setup_parameters):
""" Fixture to automatically setup virtual detector servers for testing. """
fp = sys.stdout
servers, nmods = setup_parameters
print("servers:", servers)
print("nmods:", nmods)
try:
for server in servers:
for ninterfaces in range(1,2):
if ninterfaces == 2 and server != 'jungfrau' and server != 'moench':
continue
msg = f'Starting Python API Tests for {server}'
if server == 'jungfrau' or server == 'moench':
msg += f' with {ninterfaces} interfaces'
Log(LogLevel.INFOBLUE, msg, fp)
cleanup(fp)
startDetectorVirtualServer(server, nmods, fp)
startReceiver(nmods, fp)
d = loadConfig(name=server, log_file_fp=fp, num_mods=nmods, num_frames=1, num_interfaces=ninterfaces)
#loadBasicSettings(name=server, d=d, fp=fp)
yield # run test
cleanup(fp) # teardown
except Exception as e:
traceback.print_exc(file=fp)
Log(LogLevel.ERROR, f'Tests Failed.', fp)
cleanup(fp)
+59
View File
@@ -0,0 +1,59 @@
import pytest
import sys
from conftest import session_simulator
from slsdet import Detector
from slsdet._slsdet import slsDetectorDefs
detectorType = slsDetectorDefs.detectorType
@pytest.mark.detectorintegration
def test_rx_ROI(session_simulator):
""" Test rx_ROI property of Detector class. """
det_type, num_interfaces, num_mods, d = session_simulator
assert d is not None
if d.type == detectorType.CHIPTESTBOARD or d.type == detectorType.XILINX_CHIPTESTBOARD:
pytest.skip("Skipping ROI test for ctb/xilinx_ctb detector types.")
if(d.type == detectorType.MYTHEN3 or d.type == detectorType.GOTTHARD2):
d.rx_roi = (0, 10)
roi = d.rx_roi
assert roi == [(0, 10, -1, -1)]
#d.rx_roi = [[5,15, 0, 1]] # not allowed for mythen3
d.rx_roi = [0,10, -1, -1]
assert d.rx_roi == [(0,10,-1,-1)]
d.rx_clearroi()
else:
d.rx_roi = (0, 10, 10, 20)
roi = d.rx_roi
assert roi == [(0, 10, 10, 20)]
d.rx_roi = [5,15,15,25]
assert d.rx_roi == [(5,15,15,25)]
if d.nmod > 1 and (d.type != detectorType.JUNGFRAU) or (d.numinterfaces == 2 and d.type != detectorType.EIGER):
d.rx_roi = [[0,10,0,20], [5,20,410,420]]
roi = d.rx_roi
assert roi == [(0,10,0,20), (5,20,410,420)] #in same file for jungfrau
d.rx_clearroi()
roi = d.rx_roi
assert roi == [(-1,-1,-1,-1)]
+205
View File
@@ -12,6 +12,9 @@ from utils_for_test import (
)
from slsdet import Detector
from slsdet._slsdet import slsDetectorDefs
detectorType = slsDetectorDefs.detectorType
@pytest.mark.detectorintegration
@@ -396,6 +399,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 +905,18 @@ def test_dac(session_simulator, request):
Log(LogLevel.INFOGREEN, f"{request.node.name} passed")
@pytest.mark.detectorintegration
@pytest.mark.parametrize("session_simulator",[("moench", 1, 2)],indirect=True)
def test_type(session_simulator):
d = Detector()
assert d.type == detectorType.MOENCH
@pytest.mark.detectorintegration
@pytest.mark.parametrize("session_simulator",[("moench", 1, 2), ("jungfrau", 1, 2)],indirect=True)
def test_numinterfaces(session_simulator):
d = Detector()
assert d.numinterfaces == 1
+12 -36
View File
@@ -17,46 +17,18 @@ sys.path.append(str(scripts_dir))
from slsdet import Detector, Ctb, freeSharedMemory
from utils_for_test import (
Log,
LogLevel,
cleanup,
startDetectorVirtualServer,
connectToVirtualServers,
SERVER_START_PORTNO
)
'''
scope = module =>Once per test file/module
to share expensive setup like startDetectorVirtualServer
'''
@pytest.fixture(scope="module")
def det_config():
return {
"name": "ctb",
"num_mods": 1
}
@pytest.fixture(scope="module", autouse=True)
def setup_simulator(det_config):
"""Fixture to start the detector server once and clean up at the end."""
fp = sys.stdout
cleanup(fp)
startDetectorVirtualServer(det_config["name"], det_config["num_mods"], fp)
Log(LogLevel.INFOBLUE, f'Waiting for server to start up and connect')
connectToVirtualServers(det_config["name"], det_config["num_mods"])
Log(LogLevel.INFOBLUE, f'Freeing shm before tests')
freeSharedMemory()
yield # tests run here
cleanup(fp)
from conftest import session_simulator
@pytest.mark.detectorintegration
def test_exptime_after_free_should_raise(setup_simulator):
@pytest.mark.parametrize("session_simulator",[("ctb", 1, 1)],indirect=True)
def test_exptime_after_free_should_raise(session_simulator):
Log(LogLevel.INFOBLUE, f'\nRunning test_exptime_after_free_should_raise')
@@ -78,7 +50,8 @@ def free_and_create_shm():
k.hostname = f"localhost:{SERVER_START_PORTNO}" # free and recreate shm, maps to local shm struct
@pytest.mark.detectorintegration
def test_exptime_after_not_passing_var_should_raise(setup_simulator):
@pytest.mark.parametrize("session_simulator",[("ctb", 1, 1)],indirect=True)
def test_exptime_after_not_passing_var_should_raise(session_simulator):
Log(LogLevel.INFOBLUE, f'\nRunning test_exptime_after_not_passing_var_should_raise')
@@ -102,7 +75,8 @@ def free_and_create_shm_passing_ctb_var(k):
k.hostname = f"localhost:{SERVER_START_PORTNO}" # free and recreate shm, maps to local shm struct
@pytest.mark.detectorintegration
def test_exptime_after_passing_ctb_var_should_raise(setup_simulator):
@pytest.mark.parametrize("session_simulator",[("ctb", 1, 1)],indirect=True)
def test_exptime_after_passing_ctb_var_should_raise(session_simulator):
Log(LogLevel.INFOBLUE, f'\nRunning test_exptime_after_passing_ctb_var_should_raise')
d = Ctb() # creates multi shm (assuming no shm exists)
@@ -125,7 +99,8 @@ def free_and_create_shm_returning_ctb():
return k
@pytest.mark.detectorintegration
def test_exptime_after_returning_ctb_should_raise(setup_simulator):
@pytest.mark.parametrize("session_simulator",[("ctb", 1, 1)],indirect=True)
def test_exptime_after_returning_ctb_should_raise(session_simulator):
Log(LogLevel.INFOBLUE, f'\nRunning test_exptime_after_returning_ctb_should_raise')
d = Ctb() # creates multi shm (assuming no shm exists)
@@ -148,7 +123,8 @@ def test_exptime_after_returning_ctb_should_raise(setup_simulator):
assert str(exc_info.value) == "Shared memory is invalid or freed. Close resources before access."
@pytest.mark.detectorintegration
def test_hostname_twice_acess_old_should_raise(setup_simulator):
@pytest.mark.parametrize("session_simulator",[("ctb", 1, 1)],indirect=True)
def test_hostname_twice_acess_old_should_raise(session_simulator):
Log(LogLevel.INFOBLUE, f'\nRunning test_hostname_twice_acess_old_should_raise')
d = Ctb() # creates multi shm (assuming no shm exists)
+48
View File
@@ -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)
-51
View File
@@ -1,51 +0,0 @@
import pytest
import sys
from conftest import test_with_simulators
from slsdet import Detector
from utils_for_test import (
Log,
LogLevel,
)
@pytest.mark.detectorintegration
@pytest.mark.parametrize("setup_parameters", [(["moench"], 2)], indirect=True)
def test_rx_ROI_moench(test_with_simulators, setup_parameters):
""" Test setting and getting rx_ROI property of Detector class for moench. """
d = Detector()
d.rx_roi = (0, 10, 10, 20)
roi = d.rx_roi
assert roi == [(0, 10, 10, 20)]
d.rx_roi = [5,15,15,25]
assert d.rx_roi == [(5,15,15,25)]
d.rx_roi = [[0,10,0,20], [5,20,410,420]]
roi = d.rx_roi
assert roi == [(0,10,0,20), (5,20,410,420)]
d.rx_clearroi()
roi = d.rx_roi
assert roi == [(-1,-1,-1,-1)]
@pytest.mark.detectorintegration
@pytest.mark.parametrize("setup_parameters", [(["mythen3"], 1)], indirect=True)
def test_rx_ROI_mythen(test_with_simulators, setup_parameters):
""" Test setting and getting rx_ROI property of Detector class for mythen. """
d = Detector()
d.rx_roi = (0, 10)
roi = d.rx_roi
assert roi == [(0, 10, -1, -1)]
#d.rx_roi = [[5,15, 0, 1]] # not allowed for mythen3
d.rx_roi = [0,10, -1, -1]
assert d.rx_roi == [(0,10,-1,-1)]
+2 -2
View File
@@ -1,8 +1,6 @@
# SPDX-License-Identifier: LGPL-3.0-or-other
# Copyright (C) 2021 Contributors to the SLS Detector Package
# Install fake the library
install(TARGETS slsProjectCSettings
EXPORT "${TARGETS_EXPORT_NAME}"
@@ -17,3 +15,5 @@ add_subdirectory(jungfrauDetectorServer)
add_subdirectory(mythen3DetectorServer)
add_subdirectory(gotthard2DetectorServer)
add_subdirectory(moenchDetectorServer)
add_subdirectory(matterhornServer)
@@ -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)
@@ -13,6 +13,7 @@
#include "communication_funcs_UDP.h"
#include "loadPattern.h"
#include <math.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
@@ -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 */
@@ -1793,8 +1882,10 @@ int getPowerADC(enum powerIndex index, int *retval, char *mess) {
#ifdef VIRTUAL
return 0;
#endif
// read register containing the measurement (16-bit signed), sign extend to int
*retval = (int)(int16_t)bus_r(POWER_MONITOR_BASE_REG + ((int)adcIndex << MEM_MAP_SHIFT));
// read register containing the measurement (16-bit signed), sign extend to
// int
*retval = (int)(int16_t)bus_r(POWER_MONITOR_BASE_REG +
((int)adcIndex << MEM_MAP_SHIFT));
return OK;
}
@@ -2206,13 +2297,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 +2338,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 +2355,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 +2384,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 +2608,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;
@@ -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();
@@ -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 {
@@ -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);
@@ -0,0 +1,62 @@
set(MATTERHORN_SOURCES
${CMAKE_CURRENT_SOURCE_DIR}/src/MatterhornApp.cpp
)
if(SLS_USE_SIMULATOR)
list(APPEND MATTERHORN_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/src/VirtualMatterhornServer.cpp)
add_executable(matterhornDetectorServer_virtual ${MATTERHORN_SOURCES})
target_include_directories(matterhornDetectorServer_virtual
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include
${CMAKE_CURRENT_SOURCE_DIR}/../../slsSupportLib/include
${CMAKE_CURRENT_SOURCE_DIR}/../slsDetectorServer_cpp/include)
target_link_libraries(matterhornDetectorServer_virtual
PUBLIC
slsSupportStatic
slsServerStatic)
set_target_properties(matterhornDetectorServer_virtual PROPERTIES
RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin
)
install(TARGETS matterhornDetectorServer_virtual
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
)
else()
list(APPEND MATTERHORN_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/src/MatterhornServer.cpp)
add_executable(matterhornDetectorServer ${MATTERHORN_SOURCES})
target_include_directories(matterhornDetectorServer
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include
${CMAKE_CURRENT_SOURCE_DIR}/../../slsSupportLib/include
${CMAKE_CURRENT_SOURCE_DIR}/../slsDetectorServer_cpp/include)
target_link_libraries(matterhornDetectorServer
PUBLIC
slsSupportStatic
#slsDetectorStatic
slsServerStatic)
set_target_properties(matterhornDetectorServer PROPERTIES
RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin
)
install(TARGETS matterhornDetectorServer
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
)
endif()
#target_compile_definitions(matterhornDetectorServer_virtual
# PUBLIC VIRTUAL STOP_SERVER #what is this stop server should we really have a generic ServerAPP and pass compile options to create server e.g. MatterHorn?
#)
@@ -0,0 +1,113 @@
#pragma once
#include "DetectorServer.h"
#include "TCPInterface.h"
// #include "communication_funcs.h"
#include "fmt/format.h"
#include "sls/logger.h"
#include "sls/network_utils.h"
#include "sls/sls_detector_defs.h"
#include "sls/versionAPI.h"
#include <array>
#include <cstring>
#include <functional>
#include <memory>
#include <string>
#include <unordered_map>
namespace sls {
/// @brief Base class for Matterhorn Server, can be used to implement a virtual
/// server for testing and actual server
template <typename DerivedServer>
class BaseMatterhornServer
: public DetectorServer<BaseMatterhornServer<DerivedServer>> {
public:
/**
* Constructor
* Starts up a Matterhorn server.
* Assembles a Matterhorn server using TCP and UDP detector interfaces
* throws an exception in case of failure
* @param port TCP/IP port number
*/
explicit BaseMatterhornServer(uint16_t port = DEFAULT_TCP_CNTRL_PORTNO)
: DetectorServer<BaseMatterhornServer<DerivedServer>>(port) {}
~BaseMatterhornServer() = default;
ReturnCode get_version(ServerInterface &socket);
ReturnCode get_detector_type(ServerInterface &socket);
ReturnCode initial_checks(ServerInterface &socket);
ReturnCode get_num_udp_interfaces(ServerInterface &socket) const;
/**
* @brief call function corresponding to the function ID received from the
* client and send back the result
* @param function_id the function ID received from the client
* @param socket the socket to send the result back to the client
*/
ReturnCode processFunction(const detFuncs function_id,
ServerInterface &socket);
private:
static std::string getMatterhornServerVersion();
static constexpr uint8_t numUDPInterfaces =
1; // only one udp per module for now
};
template <typename DerivedServer>
ReturnCode
BaseMatterhornServer<DerivedServer>::processFunction(const detFuncs function_id,
ServerInterface &socket) {
switch (function_id) {
default:
throw RuntimeError(
fmt::format("Function {} not implemented",
getFunctionNameFromEnum((enum detFuncs)function_id)));
}
}
template <typename DerivedServer>
ReturnCode BaseMatterhornServer<DerivedServer>::get_num_udp_interfaces(
ServerInterface &socket) const {
return static_cast<ReturnCode>(
socket.sendResult(static_cast<int>(numUDPInterfaces)));
}
template <typename DerivedServer>
ReturnCode
BaseMatterhornServer<DerivedServer>::get_version(ServerInterface &socket) {
auto version = getMatterhornServerVersion();
char version_cstr[MAX_STR_LENGTH]{};
strncpy(version_cstr, version.c_str(), version.size());
LOG(TLogLevel::logDEBUG) << "Matterhorn Server Version: " << version;
return static_cast<ReturnCode>(socket.sendResult(
version_cstr)); // TODO: check what would be possible return codes!!!
}
template <typename DerivedServer>
ReturnCode BaseMatterhornServer<DerivedServer>::get_detector_type(
ServerInterface &socket) {
int detectortype = slsDetectorDefs::detectorType::MATTERHORN;
return static_cast<ReturnCode>(socket.sendResult(detectortype));
}
template <typename DerivedServer>
std::string BaseMatterhornServer<DerivedServer>::getMatterhornServerVersion() {
return APIMATTERHORN;
}
template <typename DerivedServer>
ReturnCode
BaseMatterhornServer<DerivedServer>::initial_checks(ServerInterface &socket) {
return static_cast<DerivedServer *>(this)->initial_checks(socket);
}
} // namespace sls
@@ -0,0 +1,27 @@
#pragma once
#include "BaseMatterhornServer.h"
#include "TCPInterface.h"
#include "sls/sls_detector_defs.h"
#include <array>
#include <memory>
namespace sls {
class MatterhornServer : public BaseMatterhornServer<MatterhornServer> {
public:
/**
* Constructor
* Starts up a Matterhorn server.
* Assembles a Matterhorn server using TCP and UDP detector interfaces
* throws an exception in case of failure
* @param port TCP/IP port number
*/
explicit MatterhornServer(uint16_t port = DEFAULT_TCP_CNTRL_PORTNO);
~MatterhornServer() = default;
ReturnCode initial_checks(ServerInterface &socket);
};
} // namespace sls
@@ -0,0 +1,240 @@
// clang-format off
#include "RegisterHelperStructs.hpp"
namespace sls {
/// @brief Enum for IP cores, value are adresses
constexpr enum class IPCore : uint32_t {
MH_RO_SM_AXI = 0, // dummy adresses for now
FHDR_AXI = 1,
AURORA_STATUS = 2,
AURORA_STATUS2 = 3,
PACKETIZERREG = 4,
UNKNOWN = 5
};
// Register definitions
constexpr Register CTRL_Reg{IPCore::UNKNOWN, 0x0};
constexpr Register Status_Reg{IPCore::UNKNOWN, 0x4};
constexpr Register FPGAVersionReg{IPCore::UNKNOWN, 0x8};
constexpr Register FPGA_GIT_HEAD{IPCore::UNKNOWN, 0xc};
constexpr Register FixedPatternReg{IPCore::UNKNOWN, 0x10};
constexpr Register ApiVersionReg{IPCore::UNKNOWN, 0x14};
constexpr Register Chip_ID_Reg{IPCore::UNKNOWN, 0x18};
constexpr Register MH_SM_Ctrl_Reg{IPCore::MH_RO_SM_AXI, 0x0};
constexpr Register MH_SM_Exposure_Reg{IPCore::MH_RO_SM_AXI, 0x4};
constexpr Register MH_SM_Period_Reg{IPCore::MH_RO_SM_AXI, 0x8};
constexpr Register MH_SM_Frames_Reg{IPCore::MH_RO_SM_AXI, 0xc};
constexpr Register MH_SM_StoreLength_Reg{IPCore::MH_RO_SM_AXI, 0x10};
constexpr Register MH_SM_ResetMHLength_Reg{IPCore::MH_RO_SM_AXI, 0x14};
constexpr Register Frame_HDR_Set_Reg{IPCore::FHDR_AXI, 0x0};
constexpr Register Frame_HDR_FrameNumLSB_Reg{IPCore::FHDR_AXI, 0x4};
constexpr Register Frame_HDR_FrameNumMSB_Reg{IPCore::FHDR_AXI, 0x8};
constexpr Register Frame_HDR_TimestampLSB_Reg{IPCore::FHDR_AXI, 0xc};
constexpr Register Frame_HDR_TimestampMSB_Reg{IPCore::FHDR_AXI, 0x10};
constexpr Register Frame_HDR_ModCoord_LSB_Reg{IPCore::FHDR_AXI, 0x14};
constexpr Register Frame_HDR_ModCoord_MSB_Reg{IPCore::FHDR_AXI, 0x18};
constexpr Register Frame_HDR_PktctrMax_Reg{IPCore::FHDR_AXI, 0x1c};
constexpr Register Aurora_Valid_DW_Reg{IPCore::AURORA_STATUS, 0x0};
constexpr Register Aurora_Valid_Bytes_Reg{IPCore::AURORA_STATUS, 0x4};
constexpr Register Aurora_Busy_Up_Cycles_Reg{IPCore::AURORA_STATUS, 0x8};
constexpr Register Aurora_Hard_Errors_Reg{IPCore::AURORA_STATUS, 0xc};
constexpr Register Aurora_Soft_Errors_Reg{IPCore::AURORA_STATUS, 0x10};
constexpr Register Aurora_Channel_n_Lanes_Up_Reg{IPCore::AURORA_STATUS, 0x14};
constexpr Register Aurora_GT_PLL_Lock_Reg{IPCore::AURORA_STATUS2, 0x0};
constexpr Register PktPacketLengthReg{IPCore::PACKETIZERREG, 0xa100};
constexpr Register PktNoPacketsReg{IPCore::PACKETIZERREG, 0xa104};
constexpr Register PktCtrlReg{IPCore::PACKETIZERREG, 0xa108};
constexpr Register PktCoordReg1{IPCore::PACKETIZERREG, 0xa10c};
constexpr Register PktCoordReg2{IPCore::PACKETIZERREG, 0xa110};
// Register fields
constexpr RegisterField Power_VIO{
CTRL_Reg, 0, 0x1};
constexpr RegisterField Power_Vcc_A{
CTRL_Reg, 1, 0x1};
constexpr RegisterField Power_Vcc_B{
CTRL_Reg, 2, 0x1};
constexpr RegisterField Power_Vcc_C{
CTRL_Reg, 3, 0x1};
constexpr RegisterField Power_Vcc_D{
CTRL_Reg, 4, 0x1};
constexpr RegisterField MH_Enable_Enable{
CTRL_Reg, 5, 0x1};
constexpr RegisterField MH_Clk_Enable{
CTRL_Reg, 6, 0x1};
constexpr RegisterField sm_busy{
Status_Reg, 0, 0x1};
constexpr RegisterField FPGACompDate{
FPGAVersionReg, 0, 0xffffff};
constexpr RegisterField FPGADetType{
FPGAVersionReg, 24, 0xff};
constexpr RegisterField FPGA_GIT_HEAD{
FPGA_GIT_HEAD, 0, 0xffffffff};
constexpr RegisterField FixedPattern{
FixedPatternReg, 0, 0xffffffff};
constexpr RegisterField ApiCompDate{
ApiVersionReg, 0, 0xffffff};
constexpr RegisterField ApiDetType{
ApiVersionReg, 24, 0xff};
constexpr RegisterField ChipID{
Chip_ID_Reg, 0, 0x7};
constexpr RegisterField Start_Acquistion{
MH_SM_Ctrl_Reg, 0, 0x1};
constexpr RegisterField Stop_Acquistion{
MH_SM_Ctrl_Reg, 1, 0x1};
constexpr RegisterField MH_Readout_Exposure_Time{
MH_SM_Exposure_Reg, 0, 0xffffffff};
constexpr RegisterField MH_Readout_Period_Time{
MH_SM_Period_Reg, 0, 0xffffffff};
constexpr RegisterField MH_Readout_Frames{
MH_SM_Frames_Reg, 0, 0xffffffff};
constexpr RegisterField MH_SM_StoreLength{
MH_SM_StoreLength_Reg, 0, 0xffffffff};
constexpr RegisterField MH_SM_ResetMHLength{
MH_SM_ResetMHLength_Reg, 0, 0xffffffff};
constexpr RegisterField Frame_Hdr_Set_Framenumber{
Frame_HDR_Set_Reg, 0, 0x1};
constexpr RegisterField Frame_Hdr_Set_Timestamp{
Frame_HDR_Set_Reg, 1, 0x1};
constexpr RegisterField Frame_Hdr_Framenumber_LSB{
Frame_HDR_FrameNumLSB_Reg, 0, 0xffffffff};
constexpr RegisterField Frame_Hdr_Framenumber_MSB{
Frame_HDR_FrameNumMSB_Reg, 0, 0xffffffff};
constexpr RegisterField Frame_Hdr_Timestamp_LSB{
Frame_HDR_TimestampLSB_Reg, 0, 0xffffffff};
constexpr RegisterField Frame_Hdr_Timestamp_MSB{
Frame_HDR_TimestampMSB_Reg, 0, 0xffffffff};
constexpr RegisterField Frame_HDR_ModCoord_LSB{
Frame_HDR_ModCoord_LSB_Reg, 0, 0xffffffff};
constexpr RegisterField Frame_HDR_ModCoord_MSB{
Frame_HDR_ModCoord_MSB_Reg, 0, 0xffffffff};
constexpr RegisterField Frame_HDR_PktctrMax{
Frame_HDR_PktctrMax_Reg, 0, 0xff};
constexpr RegisterField Aurora_Number_Valid_DW{
Aurora_Valid_DW_Reg, 0, 0xffffffff};
constexpr RegisterField Aurora_Valid_Bytes{
Aurora_Valid_Bytes_Reg, 0, 0xffffffff};
constexpr RegisterField Aurora_Busy_Up_Cycles{
Aurora_Busy_Up_Cycles_Reg, 0, 0xffffffff};
constexpr RegisterField Aurora_Hard_Errors{
Aurora_Hard_Errors_Reg, 0, 0xffffffff};
constexpr RegisterField Aurora_Soft_Errors{
Aurora_Soft_Errors_Reg, 0, 0xffffffff};
constexpr RegisterField Aurora_Lanes_Up{
Aurora_Channel_n_Lanes_Up_Reg, 0, 0xf};
constexpr RegisterField Aurora_Channel_Up{
Aurora_Channel_n_Lanes_Up_Reg, 4, 0x1};
constexpr RegisterField Aurora_GT_PLL_Lock{
Aurora_GT_PLL_Lock_Reg, 0, 0x1};
constexpr RegisterField Aurora_GT_PLL_Lock_Counter{
Aurora_GT_PLL_Lock_Reg, 4, 0x1ffffff};
constexpr RegisterField PacketLength1G{
PktPacketLengthReg, 0, 0xffff};
constexpr RegisterField PacketLength10G{
PktPacketLengthReg, 16, 0xffff};
constexpr RegisterField NoPackets1G{
PktNoPacketsReg, 0, 0x3f};
constexpr RegisterField NoPackets10G{
PktNoPacketsReg, 16, 0x3f};
constexpr RegisterField NoServers{
PktCtrlReg, 0, 0x3f};
constexpr RegisterField ServerStart{
PktCtrlReg, 8, 0x1f};
constexpr RegisterField EthInterf{
PktCtrlReg, 16, 0x1};
constexpr RegisterField Coordx{
PktCoordReg1, 0, 0xffff};
constexpr RegisterField Coordy{
PktCoordReg1, 16, 0xffff};
constexpr RegisterField Coordz{
PktCoordReg2, 0, 0xffff};
} // namespace sls
// clang-format on
@@ -0,0 +1,29 @@
#include <cstdint>
#include <string_view>
namespace sls {
enum class IPCore : uint32_t; // forward declaration of IPCore enum class
struct Register {
/// @brief IP core address space
const IPCore ip_core{}; // TODO replace by enum type
/// @brief Offset of the register in bytes from the base address of the IP
/// core
const uint32_t offset_in_bytes{};
};
struct RegisterField {
/// @brief Register to which the field belongs
const Register register_{};
/// @brief Bit position of the least significant bit of the field in the
/// register
const uint32_t bit_position{};
/// @brief Bitmask for the field
const uint32_t bitmask{};
};
} // namespace sls
@@ -0,0 +1,24 @@
#include "BaseMatterhornServer.h"
namespace sls {
class VirtualMatterhornServer
: public BaseMatterhornServer<VirtualMatterhornServer> {
public:
/**
* Constructor
* Starts up a virtual Matterhorn server.
* Assembles a virtual Matterhorn server using TCP and UDP detector
* interfaces throws an exception in case of failure
* @param port TCP/IP port number
*/
explicit VirtualMatterhornServer(uint16_t port = DEFAULT_TCP_CNTRL_PORTNO);
~VirtualMatterhornServer() = default;
ReturnCode initial_checks(ServerInterface &socket);
};
} // namespace sls
@@ -0,0 +1,113 @@
#include "CommandLineOptions.h"
#include "VirtualMatterhornServer.h"
#include "sls/logger.h"
#include "sls/sls_detector_exceptions.h"
#include "sls/versionAPI.h"
#include <semaphore.h>
#include <csignal>
#include <signal.h>
#include <sys/wait.h>
#include <unistd.h>
// gettid added in glibc 2.30
#if __GLIBC__ == 2 && __GLIBC_MINOR__ < 30
#include <sys/syscall.h>
#define gettid() syscall(SYS_gettid)
#endif
using namespace sls;
pid_t pid = -1;
static volatile sig_atomic_t interruption = 0;
/**
* Control+C Interrupt Handler
* to let all the other process know to exit properly
*/
void sigInterruptHandler(int signal) {
(void)signal; // suppress unused warning if needed
interruption = 1;
}
// TODO: should be a generic ServerApp for all detectors
int main(int argc, char *argv[]) {
CommandLineOptions cli;
DetectorServerOptions opts{};
try {
opts = cli.parse(argc, argv);
} catch (sls::RuntimeError &e) {
return EXIT_FAILURE;
}
if (opts.versionRequested) {
std::cout << fmt::format("MatterhornServer Version: {}", APIMATTERHORN)
<< std::endl;
return EXIT_SUCCESS;
}
if (opts.helpRequested) {
return EXIT_SUCCESS;
}
LOG(TLogLevel::logINFOMAGENTA) << cli.printOptions();
// Register Ctrl+C handler
std::signal(SIGINT, sigInterruptHandler);
// handle locally on socket crash
signal(SIGPIPE, SIG_IGN);
pid = fork(); // fork process for control and stop server
if (pid == 0) {
// Stop server Process
LOG(TLogLevel::logINFOBLUE) << "Stop Server [" << opts.port + 1 << "]";
try {
VirtualMatterhornServer stopServer(opts.port + 1);
while (!interruption) {
pause(); // wait for signal to exit
}
} catch (...) {
kill(getppid(), SIGINT); // tell parent to exit // TODO: should then
// also return EXIT_FAILURE
}
LOG(TLogLevel::logINFOBLUE)
<< "Exiting Stop Server [ Tid: " << gettid() << " ]";
LOG(sls::logINFO) << "Exiting Stop Server";
} else if (pid > 0) {
// parent
// Control Server Process
LOG(TLogLevel::logINFOBLUE) << "Control Server [" << opts.port << "]\n";
try {
VirtualMatterhornServer server(
opts.port); // TODO use virtual if compiled with virtual
// simulators on
while (!interruption) {
pause(); // wait for signal to exit
}
} catch (...) {
LOG(sls::logINFOBLUE)
<< "Exiting Control Server [ Tid: " << gettid() << " ]";
LOG(sls::logINFO) << "Exiting Detector Server";
kill(pid, SIGINT); // tell child to exit
waitpid(pid, nullptr, 0); // wait for child to exit
return EXIT_FAILURE;
}
waitpid(pid, nullptr, 0); // wait for child to exit
LOG(sls::logINFOBLUE)
<< "Exiting Detector Control Server [ Tid: " << gettid() << " ]";
LOG(sls::logINFO) << "Exiting Detector Server";
} else {
LOG(sls::logERROR)
<< "Failed to fork process for control and stop server";
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
@@ -0,0 +1,24 @@
#include "MatterhornServer.h"
namespace sls {
MatterhornServer::MatterhornServer(uint16_t port)
: BaseMatterhornServer<MatterhornServer>(port) {
// TODO: when do i set the udp mac and ip ?
// should maybe be part of the constructor?
tcpInterface->startTCPServer();
// need a function to setup detector - e.g. set all registers etc.
}
ReturnCode MatterhornServer::initial_checks(ServerInterface &socket) {
// TODO: add more checks here, for now just return true to be able to test
// the should check firmware -client compatibility
bool initial_checks_passed = true;
return static_cast<ReturnCode>(socket.sendResult(initial_checks_passed));
}
} // namespace sls
@@ -0,0 +1,24 @@
#include "VirtualMatterhornServer.h"
namespace sls {
VirtualMatterhornServer::VirtualMatterhornServer(uint16_t port)
: BaseMatterhornServer<VirtualMatterhornServer>(port) {
udpDetails[0].srcip = LOCALHOSTIP_INT;
// should maybe be part of the constructor?
tcpInterface->startTCPServer();
// need a function to setup detector - e.g. set all registers etc.
}
ReturnCode VirtualMatterhornServer::initial_checks(ServerInterface &socket) {
// TODO: add more checks here, for now just return true to be able to test
// the should check firmware -client compatibility
bool initial_checks_passed = true;
return static_cast<ReturnCode>(socket.sendResult(initial_checks_passed));
}
} // namespace sls
@@ -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();
@@ -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
@@ -2,6 +2,7 @@
// Copyright (C) 2021 Contributors to the SLS Detector Package
#pragma once
#include "clogger.h"
#include "sls/md5.h"
#include <stdint.h> // int64_t
#include <stdio.h>
@@ -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)
@@ -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
@@ -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() {
@@ -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);
}
@@ -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
@@ -11057,9 +11095,11 @@ int spi_read(int file_des) {
#elif defined(CHIPTESTBOARDD)
// set spi to 8 bit per word (-1 comes from the firmware), set chipselect
bus_w(SPI_CTRL_REG,
((8 - 1) << SPI_CTRL_NBIT_OFST) + (1 << SPI_CTRL_CHIPSELECT_BIT));
for (int i = 0; i < n_bytes + 1; ++i) {
// TODO: should we make bus_w to this address blocking in the firmware
//
// to remove usleep ?
bus_w(SPI_WRITEDATA_REG, local_tx[i]);
usleep_bf(BFIN_SPI_WAIT_uSECONDS);
@@ -0,0 +1,64 @@
set(SOURCES
${CMAKE_CURRENT_SOURCE_DIR}/src/TCPInterface.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/CommandLineOptions.cpp
)
add_library(slsServerObject OBJECT
${SOURCES}
)
target_include_directories(slsServerObject PUBLIC
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>"
"$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>"
)
target_link_libraries(slsServerObject
PUBLIC
slsProjectOptions
slsSupportStatic
PRIVATE
slsProjectWarnings
)
set(DETECTOR_LIBRARY_TARGETS slsServerObject)
set(PUBLICHEADERS
${CMAKE_CURRENT_SOURCE_DIR}/include/TCPInterface.h
)
#Shared library
if(SLS_BUILD_SHARED_LIBRARIES)
add_library(slsServerShared SHARED $<TARGET_OBJECTS:slsServerObject>)
target_link_libraries(slsServerShared PUBLIC slsServerObject)
set_target_properties(slsServerShared PROPERTIES
VERSION ${PACKAGE_VERSION_MAJOR}.${PACKAGE_VERSION_MINOR}.${PACKAGE_VERSION_PATCH}
SOVERSION ${PACKAGE_VERSION_MAJOR}
LIBRARY_OUTPUT_NAME SlsServer
LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin
PUBLIC_HEADER "${PUBLICHEADERS}"
)
list(APPEND DETECTOR_LIBRARY_TARGETS slsServerShared)
endif(SLS_BUILD_SHARED_LIBRARIES)
#Static library
add_library(slsServerStatic STATIC $<TARGET_OBJECTS:slsServerObject>)
target_link_libraries(slsServerStatic PUBLIC slsServerObject)
set_target_properties(slsServerStatic PROPERTIES
ARCHIVE_OUTPUT_NAME SlsServerStatic
ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin
PUBLIC_HEADER "${PUBLICHEADERS}"
)
list(APPEND DETECTOR_LIBRARY_TARGETS slsServerStatic)
if((CMAKE_BUILD_TYPE STREQUAL "Release") AND SLS_LTO_AVAILABLE)
set_property(TARGET ${DETECTOR_LIBRARY_TARGETS} PROPERTY INTERPROCEDURAL_OPTIMIZATION True)
endif()
install(TARGETS ${DETECTOR_LIBRARY_TARGETS}
EXPORT "${TARGETS_EXPORT_NAME}"
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/sls
)
@@ -0,0 +1,66 @@
#include "sls/sls_detector_defs.h"
#include <array>
#include <cstdint>
#include <getopt.h>
#include <string>
namespace sls {
struct DetectorServerOptions {
// TODO: careful changed for other detectors
uint16_t port{DEFAULT_TCP_CNTRL_PORTNO};
/// @brief ignore firmware version compatibility
bool ignoreFirmwareCompatibility{false};
/// @brief safe startup - skip initial detector setup and checks
bool safeStartup{false};
bool versionRequested{false};
bool helpRequested{false};
};
template <typename Server>
struct SpecificDetectorServerOptions : DetectorServerOptions {};
// template specialization
// template <>
// struct SpecificDetectorServerOptions<BaseMatterhornServer> {};
// TODO should be a general server specific class or even shared with
// CommandLIneOptions in Receiver
class CommandLineOptions {
public:
CommandLineOptions() = default;
~CommandLineOptions() = default;
DetectorServerOptions parse(int argc, char *argv[]);
std::string printOptions() const;
private:
std::string getHelpMessage(const std::string &executable) const;
uint16_t parsePort(const char *optarg) const;
void parse_deprecated(const int &opt, char *argv[]);
DetectorServerOptions detectorserveroptions{};
static constexpr std::array<option, 8> options{
{{"help", no_argument, nullptr, 'h'},
{"version", no_argument, nullptr, 'v'},
{"port", required_argument, nullptr, 'p'},
{"ignore_fw_compatibility", no_argument, nullptr,
'f'}, // ignore firmware compatibility check
{"safe_startup", no_argument, nullptr, 's'}, // safe startup
// deprecated options for backward compatibility
{"devel", no_argument, nullptr, 'd'}, // safe_startup mode
{"update", no_argument, nullptr, 'u'}, // firmware compatibility check
{nullptr, 0, nullptr, 0}}};
inline static const char optstring[] = "hvp:fs"
"du"; // second part is deprecated
};
} // namespace sls
@@ -0,0 +1,269 @@
#pragma once
#include "TCPInterface.h"
// #include "communication_funcs.h"
#include "sls/logger.h"
#include "sls/network_utils.h"
#include "sls/sls_detector_defs.h"
#include "sls/versionAPI.h"
#include <array>
#include <cstring>
#include <functional>
#include <memory>
#include <string>
#include <unordered_map>
namespace sls {
// TODO move to defs?
/// @brief struct saving udp details (one UDP port per module)
struct UDPInfo {
uint16_t srcport{};
uint16_t dstport{};
uint64_t srcmac{};
uint64_t dstmac{};
uint32_t srcip{};
uint32_t dstip{};
};
template <typename DerivedDetectorServer> class DetectorServer {
public:
/**
* Constructor
* Creates a detector server.
* Assembles a detector server using TCP and UDP detector interfaces
* throws an exception in case of failure
* @param port TCP/IP port number
*/
explicit DetectorServer(uint16_t port = DEFAULT_TCP_CNTRL_PORTNO);
protected:
/// @brief TCP/IP interface for communication with the client
std::unique_ptr<TCPInterface> tcpInterface;
std::array<UDPInfo, 1>
udpDetails{}; // TODO: for now only one receiver per module
/// @brief TODO what is this?
bool updateMode{true};
private:
ReturnCode processFunction(const detFuncs function_id,
ServerInterface &socket);
// TODO dont know what this does?
ReturnCode get_update_mode(ServerInterface &socket) const;
ReturnCode get_source_udp_mac(ServerInterface &socket) const;
ReturnCode set_source_udp_mac(ServerInterface &socket);
ReturnCode get_source_udp_ip(ServerInterface &socket) const;
ReturnCode set_source_udp_ip(ServerInterface &socket);
ReturnCode get_source_udp_port(ServerInterface &socket) const;
ReturnCode set_destination_udp_mac(ServerInterface &socket);
ReturnCode get_destination_udp_mac(ServerInterface &socket) const;
ReturnCode set_destination_udp_ip(ServerInterface &socket);
ReturnCode get_destination_udp_ip(ServerInterface &socket) const;
ReturnCode set_destination_udp_port(ServerInterface &socket);
ReturnCode get_destination_udp_port(ServerInterface &socket) const;
};
template <typename DerivedDetectorServer>
DetectorServer<DerivedDetectorServer>::DetectorServer(uint16_t port) {
validatePortNumber(port);
udpDetails[0].srcport = DEFAULT_UDP_SRC_PORTNO;
udpDetails[0].dstport = DEFAULT_UDP_DST_PORTNO;
std::function<ReturnCode(const detFuncs &, ServerInterface &)> fn =
[this](const detFuncs &function_id, ServerInterface &socket) {
return this->processFunction(function_id, socket);
};
tcpInterface = std::make_unique<TCPInterface>(fn, port);
}
template <typename DerivedDetectorServer>
ReturnCode DetectorServer<DerivedDetectorServer>::processFunction(
const detFuncs function_id, ServerInterface &socket) {
switch (function_id) {
case detFuncs::F_GET_SERVER_VERSION:
return static_cast<DerivedDetectorServer *>(this)->get_version(socket);
case detFuncs::F_GET_DETECTOR_TYPE:
return static_cast<DerivedDetectorServer *>(this)->get_detector_type(
socket);
case detFuncs::F_INITIAL_CHECKS:
return static_cast<DerivedDetectorServer *>(this)->initial_checks(
socket);
case detFuncs::F_GET_NUM_INTERFACES:
return static_cast<DerivedDetectorServer *>(this)
->get_num_udp_interfaces(socket);
case detFuncs::F_GET_UPDATE_MODE:
return get_update_mode(socket);
case detFuncs::F_SET_SOURCE_UDP_MAC:
return set_source_udp_mac(socket);
case detFuncs::F_GET_SOURCE_UDP_MAC:
return get_source_udp_mac(socket);
case detFuncs::F_SET_SOURCE_UDP_IP:
return set_source_udp_ip(socket);
case detFuncs::F_GET_SOURCE_UDP_IP:
return get_source_udp_ip(socket);
case detFuncs::F_SET_DEST_UDP_MAC:
return set_destination_udp_mac(socket);
case detFuncs::F_GET_DEST_UDP_MAC:
return get_destination_udp_mac(socket);
case detFuncs::F_SET_DEST_UDP_IP:
return set_destination_udp_ip(socket);
case detFuncs::F_GET_DEST_UDP_IP:
return get_destination_udp_ip(socket);
case detFuncs::F_SET_DEST_UDP_PORT:
return set_destination_udp_port(socket);
case detFuncs::F_GET_DEST_UDP_PORT:
return get_destination_udp_port(socket);
default:
LOG(logDEBUG) << "Checking specific server functions for function ID: "
<< function_id;
// process detector specific functions
static_cast<DerivedDetectorServer *>(this)->processFunction(function_id,
socket);
}
return ReturnCode::FAIL;
}
template <typename DerivedDetectorServer>
ReturnCode DetectorServer<DerivedDetectorServer>::get_update_mode(
ServerInterface &socket) const {
return static_cast<ReturnCode>(
socket.sendResult(static_cast<int>(updateMode)));
}
template <typename DerivedDetectorServer>
ReturnCode DetectorServer<DerivedDetectorServer>::set_source_udp_mac(
ServerInterface &socket) {
uint64_t newsrcudpMac;
try {
int ret = socket.Receive<uint64_t>(newsrcudpMac);
} catch (const SocketError &e) {
LOG(logERROR) << "Failed to receive new source UDP MAC address: "
<< e.what();
return ReturnCode::FAIL;
}
udpDetails[0].srcmac = newsrcudpMac;
// TODO: configuremac, check unicast address
return ReturnCode::OK;
}
template <typename DerivedDetectorServer>
ReturnCode DetectorServer<DerivedDetectorServer>::get_source_udp_mac(
ServerInterface &socket) const {
return static_cast<ReturnCode>(socket.sendResult(udpDetails[0].srcmac));
}
template <typename DerivedDetectorServer>
ReturnCode DetectorServer<DerivedDetectorServer>::set_source_udp_ip(
ServerInterface &socket) {
uint32_t newSrcIp;
try {
int ret = socket.Receive(newSrcIp);
} catch (const SocketError &e) {
LOG(logERROR) << "Failed to receive new source UDP IP address: "
<< e.what();
return ReturnCode::FAIL;
}
udpDetails[0].srcip = newSrcIp;
return ReturnCode::OK;
}
template <typename DerivedDetectorServer>
ReturnCode DetectorServer<DerivedDetectorServer>::get_source_udp_ip(
ServerInterface &socket) const {
return static_cast<ReturnCode>(socket.sendResult(udpDetails[0].srcip));
}
template <typename DerivedDetectorServer>
ReturnCode DetectorServer<DerivedDetectorServer>::set_destination_udp_mac(
ServerInterface &socket) {
uint64_t newDstMac;
try {
int ret = socket.Receive<uint64_t>(newDstMac);
} catch (const SocketError &e) {
LOG(logERROR) << "Failed to receive new destination UDP MAC address: "
<< e.what();
return ReturnCode::FAIL;
}
udpDetails[0].dstmac = newDstMac;
// TODO: configuremac, check unicast address
return ReturnCode::OK;
}
template <typename DerivedDetectorServer>
ReturnCode DetectorServer<DerivedDetectorServer>::get_destination_udp_mac(
ServerInterface &socket) const {
return static_cast<ReturnCode>(socket.sendResult(udpDetails[0].dstmac));
}
template <typename DerivedDetectorServer>
ReturnCode DetectorServer<DerivedDetectorServer>::set_destination_udp_ip(
ServerInterface &socket) {
uint32_t newDstIp;
try {
int ret = socket.Receive(newDstIp);
} catch (const SocketError &e) {
LOG(logERROR) << "Failed to receive new destination UDP IP address: "
<< e.what();
return ReturnCode::FAIL;
}
udpDetails[0].dstip = newDstIp;
return ReturnCode::OK;
}
template <typename DerivedDetectorServer>
ReturnCode DetectorServer<DerivedDetectorServer>::get_destination_udp_ip(
ServerInterface &socket) const {
return static_cast<ReturnCode>(socket.sendResult(udpDetails[0].dstip));
}
template <typename DerivedDetectorServer>
ReturnCode DetectorServer<DerivedDetectorServer>::set_destination_udp_port(
ServerInterface &socket) {
uint16_t newDstPort;
try {
int ret = socket.Receive(newDstPort);
} catch (const SocketError &e) {
LOG(logERROR) << "Failed to receive new destination UDP port number: "
<< e.what();
return ReturnCode::FAIL;
}
udpDetails[0].dstport = newDstPort;
return ReturnCode::OK;
}
template <typename DerivedDetectorServer>
ReturnCode DetectorServer<DerivedDetectorServer>::get_destination_udp_port(
ServerInterface &socket) const {
return static_cast<ReturnCode>(socket.sendResult(udpDetails[0].dstport));
};
} // namespace sls
@@ -0,0 +1,60 @@
#pragma once
#include "sls/ServerSocket.h"
#include "sls/sls_detector_defs.h"
#include "sls/sls_detector_funcs.h"
#include <atomic>
#include <functional>
#include <thread>
#include <unordered_map>
namespace sls {
/**
* @brief TCPInterface class handles communication and processing of commands
* from Client to Server.
*/
class TCPInterface {
public:
~TCPInterface();
TCPInterface(std::function<ReturnCode(const detFuncs &, ServerInterface &)>
&processFunction_,
const uint16_t portNumber = DEFAULT_TCP_CNTRL_PORTNO);
/// @brief creates tcp thread
void startTCPServer();
std::atomic<bool> killTcpThread{false};
private:
/**
* @brief starts the TCP/IP server to listen for client commands and process
* them
*/
void startTCPServerClientConnection();
/**
* @brief decodes the received command and calls the corresponding function
* @param function_id The ID of the function recived by the server and to
* be executed
*/
ReturnCode processReceivedData(const detFuncs function_id,
ServerInterface &socket);
/// @brief map of function IDs and corresponding functions
std::function<ReturnCode(const detFuncs &, ServerInterface &)>
processFunction;
/// @brief TCP/IP port number for the detector server
uint16_t portNumber{};
/// @brief socket for TCP/IP communication with the client
ServerSocket server;
/// @brief thread for running the TCP/IP server
std::unique_ptr<std::thread> tcpThread;
};
} // namespace sls
@@ -0,0 +1,116 @@
#include "CommandLineOptions.h"
#include "sls/ToString.h"
#include "sls/sls_detector_exceptions.h"
#include <cstdint>
#include <fmt/format.h>
#include <getopt.h>
#include <iostream>
namespace sls {
uint16_t CommandLineOptions::parsePort(const char *optarg) const {
uint16_t val = 0; // TODO: in c code its unsigned int
try {
val = sls::StringTo<uint16_t>(optarg);
} catch (const std::exception &e) {
throw sls::RuntimeError(fmt::format(
"Could not parse port number {}. {}", optarg, e.what()));
}
if (val < 1024) {
throw sls::RuntimeError(
"Invalid/ privileged port number parsed. Min: 1024.");
}
return val;
}
std::string
CommandLineOptions::getHelpMessage(const std::string &executable) const {
// TODO: update if we keep it Matterhonr specific - refactor a bit better -
// e.g. if compiled with detector macro
std::string helpmessage = fmt::format(
"Usage: {}"
" [arguments]\n"
"Possible arguments are:\n"
"\t-v, --version : Software version\n"
"\t-p, --port <port> : TCP communication port with client. "
"\n"
"\t-s, --safe_startup : Safe startup mode. Skips initial "
"detector setup and checks. \n"
"\t-f, --ignore_fw_compatibility : Ignore firmware compatibility "
"check. \n",
executable);
return helpmessage;
}
void CommandLineOptions::parse_deprecated(const int &opt, char *argv[]) {
switch (opt) {
case 'd':
std::cout << "Warning: -d/--devel option is deprecated. Use "
"-l/--safe_startup instead."
<< std::endl;
detectorserveroptions.safeStartup = true;
break;
case 'u':
std::cout << "Warning: -u/--update option is deprecated. Use "
"-f/--ignore_fw_compatibility instead."
<< std::endl;
detectorserveroptions.ignoreFirmwareCompatibility = true;
break;
default:
throw std::runtime_error(fmt::format("Wrong command line arguments. {}",
getHelpMessage(argv[0])));
}
}
std::string CommandLineOptions::printOptions() const {
std::string msg = "setting up detector server";
if (detectorserveroptions.ignoreFirmwareCompatibility) {
msg += " skipping firmware compatibility checks";
msg += detectorserveroptions.safeStartup ? " and" : "";
}
if (detectorserveroptions.safeStartup) {
msg += " in safe startup mode e.g. skipping any initial detector setup "
"and checks";
}
return msg;
}
DetectorServerOptions CommandLineOptions::parse(int argc, char *argv[]) {
int opt, option_index = 0;
while ((opt = getopt_long(argc, argv, optstring, options.data(),
&option_index)) != -1) {
switch (opt) {
case 'h':
std::cout << getHelpMessage(argv[0]) << std::endl;
detectorserveroptions.helpRequested = true; // to exit in main
break;
case 'v':
detectorserveroptions.versionRequested = true; // to exit in main
break;
case 'p':
detectorserveroptions.port = parsePort(optarg);
break;
case 'f':
detectorserveroptions.ignoreFirmwareCompatibility = true;
break;
case 's':
detectorserveroptions.safeStartup = true;
break;
default:
parse_deprecated(opt, argv); // to handle deprecated options and
// throw error for wrong options
}
}
return detectorserveroptions;
}
} // namespace sls
@@ -0,0 +1,95 @@
#include "TCPInterface.h"
#include "fmt/format.h"
#include "sls/logger.h"
#include "sls/string_utils.h"
#include <unistd.h>
namespace sls {
TCPInterface::TCPInterface(
std::function<ReturnCode(const detFuncs &, ServerInterface &)>
&processFunction_,
const uint16_t portNumber_)
: processFunction(processFunction_), portNumber(portNumber_),
server(portNumber_) {
// validatePortNumber(portNumber); TODO: where to validate?
}
TCPInterface::~TCPInterface() {
killTcpThread = true; // mmh but if the receiver is stuck in a function,
// this will be of no help
LOG(logINFO) << "Shutting down TCP Socket on port " << portNumber;
server.shutdown();
LOG(logDEBUG) << "TCP Socket closed on port " << portNumber;
if (tcpThread && tcpThread->joinable()) {
tcpThread->join();
}
}
void TCPInterface::startTCPServer() {
tcpThread = std::make_unique<std::thread>(
&TCPInterface::startTCPServerClientConnection, this);
}
void TCPInterface::startTCPServerClientConnection() {
LOG(logINFO) << "SLS Server starting TCP Server on port " << portNumber
<< '\n';
int function_id{}; // TODO should it be an enum type
while (!killTcpThread) {
try {
auto socket = server.accept();
try {
socket.Receive(function_id);
if (function_id < 0 || function_id >= NUM_DET_FUNCTIONS) {
throw RuntimeError(fmt::format(
"{}:{}", UNRECOGNIZED_FNUM_ENUM,
getFunctionNameFromEnum((enum detFuncs)function_id)));
}
auto returncode = processReceivedData(
static_cast<detFuncs>(function_id), socket);
if (returncode == FAIL) {
throw RuntimeError(fmt::format(
"Error processing command with fnum: {}",
getFunctionNameFromEnum((enum detFuncs)function_id)));
}
} catch (const RuntimeError &e) {
// We had an error needs to be sent to client
char mess[MAX_STR_LENGTH]{};
LOG(logERROR) << "Error processing command: " << e.what();
strcpy_safe(mess, e.what());
socket.Send(slsDetectorDefs::FAIL);
socket.Send(mess);
}
// TODO handle exiting server if tcp command was to exit server
} catch (const RuntimeError &e) {
LOG(logERROR) << "Accept failed: " << e.what();
}
}
LOG(logINFOBLUE) << "Exiting TCP Server";
}
ReturnCode TCPInterface::processReceivedData(const detFuncs function_id,
ServerInterface &socket) {
LOG(logDEBUG1) << "calling function fnum: " << function_id << " ("
<< getFunctionNameFromEnum((enum detFuncs)function_id)
<< ")";
ReturnCode returncode = processFunction(function_id, socket);
LOG(logDEBUG1) << "Function "
<< getFunctionNameFromEnum((enum detFuncs)function_id)
<< " finished";
return returncode;
}
} // namespace sls
@@ -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;
}
@@ -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();
@@ -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
@@ -54,6 +54,9 @@ class Caller {
return ToString(value, unit);
}
std::string OutString(const Result<defs::Hz> &value,
const std::string &unit);
std::vector<std::string> getAllCommands();
std::map<std::string, std::string> 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},
@@ -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
@@ -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
}
@@ -2412,7 +2436,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=""
@@ -2465,7 +2489,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
@@ -2575,12 +2599,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=""
@@ -2684,6 +2708,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() {
@@ -2777,13 +2811,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
@@ -2795,13 +2829,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
@@ -2810,7 +2844,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
@@ -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
}
@@ -2336,7 +2360,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=""
@@ -2389,7 +2413,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
@@ -2499,12 +2523,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=""
@@ -2608,6 +2632,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() {
@@ -2701,13 +2735,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
@@ -2719,13 +2753,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
@@ -2734,7 +2768,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
+89 -34
View File
@@ -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
@@ -1919,19 +1981,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
@@ -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')
@@ -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']:
@@ -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:
@@ -10597,9 +10721,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:
@@ -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
+7 -1
View File
@@ -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<time::ns>(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<defs::Hz>(tmp_freq, $output[1]$);
```
- convert_to_time and convert_to_freq: takes three parameters: input[0], input[1], output
```cpp
auto output = StringTo<time::ns>(input[0], input[1]);
```
+17 -17
View File
@@ -1614,20 +1614,26 @@ class Detector {
/** [CTB] */
void setNumberOfAnalogSamples(int value, Positions pos = {});
/** [CTB] in MHz, [XCTB] in kHz */
Result<int> getADCClock(Positions pos = {}) const;
/** [CTB][XCTB] */
Result<defs::Hz> 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<int> getRUNClock(Positions pos = {}) const;
/** [CTB][XCTB] */
Result<defs::Hz> 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<int> getSYNCClock(Positions pos = {}) const;
/** [CTB][XCTB] */
Result<defs::Hz> getDBITClock(Positions pos = {}) const;
/** [CTB][XCTB] */
void setDBITClock(defs::Hz val, Positions pos = {});
/** [CTB][XCTB] */
Result<defs::Hz> getSYNCClock(Positions pos = {}) const;
/** gets list of power enums */
std::vector<defs::powerIndex> getPowerList() const;
@@ -1722,12 +1728,6 @@ class Detector {
*/
void setReadoutMode(defs::readoutMode value, Positions pos = {});
/** [CTB] in MHz, [XCTB] in kHz */
Result<int> getDBITClock(Positions pos = {}) const;
/** [CTB] in MHz, [XCTB] in kHz */
void setDBITClock(int value_in_MHz, Positions pos = {});
/** [CTB] */
Result<int> getExternalSamplingSource(Positions pos = {}) const;
@@ -1935,7 +1935,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<std::string> getPatterFileName(Positions pos = {}) const;
Result<std::string> getPatternFileName(Positions pos = {}) const;
/** [CTB][Mythen3][Xilinx CTB] Loads ASCII pattern file directly to server
* (instead of executing line by line)*/
+3
View File
@@ -38,6 +38,7 @@ template <class T, class Allocator = std::allocator<T>> class Result {
template <typename V, typename = typename std::enable_if<
std::is_integral<V>::value &&
(std::is_same<T, time::ns>::value ||
std::is_same<T, defs::Hz>::value ||
std::is_same<T, bool>::value)>::type>
Result(const Result<V> &from) {
vec.reserve(from.size());
@@ -49,6 +50,7 @@ template <class T, class Allocator = std::allocator<T>> class Result {
template <typename V, typename = typename std::enable_if<
std::is_integral<V>::value &&
(std::is_same<T, time::ns>::value ||
std::is_same<T, defs::Hz>::value ||
std::is_same<T, bool>::value)>::type>
Result(Result<V> &from) {
vec.reserve(from.size());
@@ -60,6 +62,7 @@ template <class T, class Allocator = std::allocator<T>> class Result {
template <typename V, typename = typename std::enable_if<
std::is_integral<V>::value &&
(std::is_same<T, time::ns>::value ||
std::is_same<T, defs::Hz>::value ||
std::is_same<T, bool>::value)>::type>
Result(Result<V> &&from) {
vec.reserve(from.size());
+117 -34
View File
@@ -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<int>(args[0]);
std::string tmp_freq(args[0]);
std::string unit = RemoveUnit(tmp_freq);
auto converted_freq = StringTo<defs::Hz>(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<defs::Hz>(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<int>{det_id});
os << OutString(t) << '\n';
}
if (args.size() == 1) {
auto t = det->getADCClock(std::vector<int>{det_id});
os << OutString(t, args[0]) << '\n';
}
}
if (action == slsDetectorDefs::PUT_ACTION) {
if (args.size() == 1) {
auto arg0 = StringTo<int>(args[0]);
det->setADCClock(arg0, std::vector<int>{det_id});
os << args.front() << '\n';
std::string tmp_freq(args[0]);
std::string unit = RemoveUnit(tmp_freq);
auto converted_freq = StringTo<defs::Hz>(tmp_freq, unit);
det->setADCClock(converted_freq, std::vector<int>{det_id});
os << args[0] << '\n';
}
if (args.size() == 2) {
auto converted_freq = StringTo<defs::Hz>(args[0], args[1]);
det->setADCClock(converted_freq, std::vector<int>{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<int>(args[0]);
std::string tmp_freq(args[0]);
std::string unit = RemoveUnit(tmp_freq);
auto converted_freq = StringTo<defs::Hz>(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<defs::Hz>(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<int>{det_id});
os << OutString(t) << '\n';
}
if (args.size() == 1) {
auto t = det->getDBITClock(std::vector<int>{det_id});
os << OutString(t, args[0]) << '\n';
}
}
if (action == slsDetectorDefs::PUT_ACTION) {
if (args.size() == 1) {
auto arg0 = StringTo<int>(args[0]);
det->setDBITClock(arg0, std::vector<int>{det_id});
os << args.front() << '\n';
std::string tmp_freq(args[0]);
std::string unit = RemoveUnit(tmp_freq);
auto converted_freq = StringTo<defs::Hz>(tmp_freq, unit);
det->setDBITClock(converted_freq, std::vector<int>{det_id});
os << args[0] << '\n';
}
if (args.size() == 2) {
auto converted_freq = StringTo<defs::Hz>(args[0], args[1]);
det->setDBITClock(converted_freq, std::vector<int>{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<int>{det_id});
auto t = det->getPatternFileName(std::vector<int>{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<int>(args[0]);
std::string tmp_freq(args[0]);
std::string unit = RemoveUnit(tmp_freq);
auto converted_freq = StringTo<defs::Hz>(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<defs::Hz>(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<int>{det_id});
os << OutString(t) << '\n';
}
if (args.size() == 1) {
auto t = det->getRUNClock(std::vector<int>{det_id});
os << OutString(t, args[0]) << '\n';
}
}
if (action == slsDetectorDefs::PUT_ACTION) {
if (args.size() == 1) {
auto arg0 = StringTo<int>(args[0]);
det->setRUNClock(arg0, std::vector<int>{det_id});
os << args.front() << '\n';
std::string tmp_freq(args[0]);
std::string unit = RemoveUnit(tmp_freq);
auto converted_freq = StringTo<defs::Hz>(tmp_freq, unit);
det->setRUNClock(converted_freq, std::vector<int>{det_id});
os << args[0] << '\n';
}
if (args.size() == 2) {
auto converted_freq = StringTo<defs::Hz>(args[0], args[1]);
det->setRUNClock(converted_freq, std::vector<int>{det_id});
os << args[0] << args[1] << '\n';
}
}
@@ -13101,21 +13176,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 {
@@ -13130,6 +13208,11 @@ std::string Caller::syncclk(int action) {
auto t = det->getSYNCClock(std::vector<int>{det_id});
os << OutString(t) << '\n';
}
if (args.size() == 1) {
auto t = det->getSYNCClock(std::vector<int>{det_id});
os << OutString(t, args[0]) << '\n';
}
}
return os.str();
+4
View File
@@ -54,6 +54,9 @@ class Caller {
return ToString(value, unit);
}
std::string OutString(const Result<defs::Hz> &value,
const std::string &unit);
std::vector<std::string> getAllCommands();
std::map<std::string, std::string> GetDeprecatedCommands();
std::string list(int action);
@@ -422,6 +425,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},
+25
View File
@@ -11,6 +11,14 @@
namespace sls {
// some helper functions to print
std::string Caller::OutString(const Result<defs::Hz> &value,
const std::string &unit) {
auto u = parseFrequencyUnit(unit);
if (value.equal())
return ToString(value.front(), u);
return ToString(value, u);
}
std::vector<std::string> Caller::getAllCommands() {
std::vector<std::string> 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
+18 -18
View File
@@ -2148,25 +2148,34 @@ void Detector::setNumberOfAnalogSamples(int value, Positions pos) {
pimpl->Parallel(&Module::setNumberOfAnalogSamples, pos, value);
}
Result<int> Detector::getADCClock(Positions pos) const {
Result<defs::Hz> 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<int> Detector::getRUNClock(Positions pos) const {
Result<defs::Hz> 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<int> Detector::getSYNCClock(Positions pos) const {
Result<defs::Hz> 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<defs::Hz> Detector::getSYNCClock(Positions pos) const {
return pimpl->Parallel(&Module::getClockFrequency, pos, defs::SYNC_CLOCK);
}
@@ -2314,15 +2323,6 @@ void Detector::setReadoutMode(defs::readoutMode value, Positions pos) {
pimpl->Parallel(&Module::setReadoutMode, pos, value);
}
Result<int> 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<int> Detector::getSlowADC(defs::dacIndex index, Positions pos) const {
if (index < defs::SLOW_ADC0 || index > defs::SLOW_ADC7) {
throw RuntimeError("Unknown Slow ADC Index");
@@ -2613,8 +2613,8 @@ void Detector::configureTransceiver(Positions pos) {
// Pattern
Result<std::string> Detector::getPatterFileName(Positions pos) const {
return pimpl->Parallel(&Module::getPatterFileName, pos);
Result<std::string> Detector::getPatternFileName(Positions pos) const {
return pimpl->Parallel(&Module::getPatternFileName, pos);
}
void Detector::setPattern(const std::string &fname, Positions pos) {
+1 -1
View File
@@ -196,7 +196,7 @@ void DetectorImpl::setHostname(const std::vector<std::string> &name) {
}
void DetectorImpl::addModule(const std::string &name) {
LOG(logINFO) << "Adding module " << name;
LOG(TLogLevel::logINFO) << "Adding module " << name;
auto host = verifyUniqueDetHost(name);
std::string hostname = host.first;
uint16_t port = host.second;
+8 -4
View File
@@ -50,8 +50,6 @@ std::string Module::getHostname() const { return shm()->hostname; }
void Module::setHostname(const std::string &hostname,
const bool initialChecks) {
strcpy_safe(shm()->hostname, hostname.c_str());
auto client = DetectorSocket(shm()->hostname, shm()->controlPort);
client.close();
try {
checkDetectorVersionCompatibility();
initialDetectorServerChecks();
@@ -87,9 +85,11 @@ std::string Module::getControlServerLongVersion() const {
// throw with old server version (sends 8 bytes)
catch (RuntimeError &e) {
std::string emsg = std::string(e.what());
if (emsg.find(F_GET_SERVER_VERSION) && emsg.find("8 bytes")) {
throwDeprecatedServerVersion();
}
throw;
}
}
@@ -146,7 +146,6 @@ std::string Module::getReceiverSoftwareVersion() const {
// static function
slsDetectorDefs::detectorType
Module::getTypeFromDetector(const std::string &hostname, uint16_t cport) {
LOG(logDEBUG1) << "Getting Module type ";
ClientSocket socket("Detector", hostname, cport);
socket.Send(F_GET_DETECTOR_TYPE);
socket.setFnum(F_GET_DETECTOR_TYPE);
@@ -2669,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;
@@ -3515,6 +3514,9 @@ void Module::initialDetectorServerChecks() {
void Module::checkDetectorVersionCompatibility() {
std::string detServers[2] = {getControlServerLongVersion(),
getStopServerLongVersion()};
LOG(logDEBUG1)
<< "Checking detector version compatibility with client version "
<< detServers[0] << " and " << detServers[1];
for (int i = 0; i != 2; ++i) {
// det and client (sem. versioning)
Version det(detServers[i]);
@@ -3563,6 +3565,8 @@ const std::string Module::getDetectorAPI() const {
return APIGOTTHARD2;
case XILINX_CHIPTESTBOARD:
return APIXILINXCTB;
case MATTERHORN:
return APIMATTERHORN;
default:
throw NotImplementedError(
"Detector type not implemented to get Detector API");
+1 -1
View File
@@ -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();
+22
View File
@@ -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;
}
@@ -3489,6 +3507,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");
@@ -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});
+1 -2
View File
@@ -85,7 +85,6 @@ void ClientInterface::startTCPServer() {
<< '\n';
while (!killTcpThread) {
LOG(logDEBUG1) << "Start accept loop";
try {
auto socket = server.accept();
try {
@@ -96,7 +95,7 @@ void ClientInterface::startTCPServer() {
// We had an error needs to be sent to client
char mess[MAX_STR_LENGTH]{};
strcpy_safe(mess, e.what());
socket.Send(FAIL);
socket.Send(slsDetectorDefs::FAIL);
socket.Send(mess);
}
// if tcp command was to exit server
+1 -1
View File
@@ -95,7 +95,7 @@ target_link_libraries(slsSupportObject
slsProjectOptions
${STD_FS_LIB} # from helpers.cmake
Threads::Threads # slsDetector and Receiver need this
fmt::fmt
PRIVATE
slsProjectWarnings
md5sls
+1
View File
@@ -3,6 +3,7 @@
#pragma once
#include "sls/TypeTraits.h"
#include "sls/logger.h"
#include <cstddef>
#include <cstdint>
#include <iostream>
@@ -3,6 +3,8 @@
#pragma once
#include "sls/DataSocket.h"
#include "sls/logger.h"
namespace sls {
class ServerInterface;
}
+49
View File
@@ -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 T>
typename std::enable_if<std::is_floating_point<T>::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 T>
typename std::enable_if<is_container<T>::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 <typename T, std::enable_if_t<sls::is_duration<T>::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 <typename T, std::enable_if_t<sls::is_frequency<T>::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<int>(fval * 1e6));
} else if (unitLower == "khz") {
return T(static_cast<int>(fval * 1e3));
} else if (unitLower.empty() || unitLower == "hz") {
return T(static_cast<int>(fval));
} else {
throw RuntimeError(
"Invalid unit in conversion from string to frequency");
}
}
template <typename T> T StringTo(const std::string &t) {
std::string tmp{t};
auto unit = RemoveUnit(tmp);
+7
View File
@@ -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 <type_traits>
#include <vector>
@@ -120,4 +122,9 @@ struct has_bool_isValid : std::false_type {};
template <typename T>
struct has_bool_isValid<T, std::void_t<decltype(std::declval<T>().isValid)>>
: std::is_same<decltype(std::declval<T>().isValid), bool> {};
template <typename T> struct is_frequency : std::false_type {};
template <> struct is_frequency<defs::Hz> : std::true_type {};
} // namespace sls
+2 -7
View File
@@ -27,11 +27,6 @@ enum TLogLevel {
logDEBUG5
};
// Compiler should optimize away anything below this value
#ifndef LOG_MAX_REPORTING_LEVEL
#define LOG_MAX_REPORTING_LEVEL sls::logINFO
#endif
#define __AT__ \
std::string(__FILE__) + std::string("::") + std::string(__func__) + \
std::string("(): ")
@@ -43,7 +38,7 @@ enum TLogLevel {
class Logger {
std::ostringstream os;
TLogLevel level = LOG_MAX_REPORTING_LEVEL;
TLogLevel level = ReportingLevel();
public:
Logger() = default;
@@ -55,7 +50,7 @@ class Logger {
}
static TLogLevel &ReportingLevel() { // singelton eeh
static TLogLevel reportingLevel = logINFO;
static TLogLevel reportingLevel = LOG_MAX_REPORTING_LEVEL;
return reportingLevel;
}
+28 -2
View File
@@ -46,6 +46,9 @@
#define DEFAULT_UDP_SRC_PORTNO 32410
#define DEFAULT_UDP_DST_PORTNO 50001
/** for virtual detectors */
#define LOCALHOSTIP_INT 2130706433
#define MAX_UDP_DESTINATION 32
#define SLS_DETECTOR_HEADER_VERSION 0x2
@@ -82,8 +85,13 @@
#define DEFAULT_STREAMING_TIMER_IN_MS 500
#define NUM_RX_THREAD_IDS 9
// NOLINTEND(cppcoreguidelines-macro-usage)
#ifdef __cplusplus
// TODO: why are all these defs inside a class? - why not static
enum ReturnCode { OK = 0, FAIL = 1 };
class slsDetectorDefs {
public:
#endif
@@ -98,7 +106,9 @@ class slsDetectorDefs {
MOENCH,
MYTHEN3,
GOTTHARD2,
XILINX_CHIPTESTBOARD
XILINX_CHIPTESTBOARD,
MATTERHORN // TODO: maybe better to have it under a namespace
// slsDetectorDefs instead of grouped in a class
};
/** return values */
@@ -211,6 +221,16 @@ class slsDetectorDefs {
std::map<std::string, std::string> 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,
@@ -758,6 +778,13 @@ struct detParameters {
nChipY = 1;
nDacs = 14;
break;
case slsDetectorDefs::detectorType::MATTERHORN:
nChanX = 256;
nChanY = 256;
nChipX = 4;
nChipY = 2;
nDacs = 31;
break;
default:
throw sls::RuntimeError("Unknown detector type! " +
std::to_string(type));
@@ -837,7 +864,6 @@ typedef struct {
#endif
#ifdef __cplusplus
// TODO! discuss this
#include <vector> //hmm... but currently no way around
namespace sls {
+10 -9
View File
@@ -1,12 +1,13 @@
// SPDX-License-Identifier: LGPL-3.0-or-other
// Copyright (C) 2021 Contributors to the SLS Detector Package
/** API versions */
#define APILIB "0.0.0 0x250909"
#define APIRECEIVER "0.0.0 0x250822"
#define APICTB "0.0.0 0x260427"
#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 APIJUNGFRAU "0.0.0 0x260424"
#define APIMYTHEN3 "0.0.0 0x260427"
#define APILIB "0.0.0 0x250909"
#define APIRECEIVER "0.0.0 0x250822"
#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 0x260506"
#define APIJUNGFRAU "0.0.0 0x260424"
#define APIMYTHEN3 "0.0.0 0x260506"
#define APIMATTERHORN "0.0.0 0x260212"
+2
View File
@@ -52,9 +52,11 @@ ServerInterface ServerSocket::accept() {
if (newSocket == -1) {
throw SocketError("Server ERROR: socket accept failed\n");
}
char tc[INET_ADDRSTRLEN]{};
inet_ntop(AF_INET, &(clientAddr.sin_addr), tc, INET_ADDRSTRLEN);
thisClient = IpAddr{tc};
// Set socket buffer size
return ServerInterface(newSocket);
}
+34
View File
@@ -221,6 +221,8 @@ std::string ToString(const defs::detectorType s) {
return std::string("Gotthard2");
case defs::XILINX_CHIPTESTBOARD:
return std::string("Xilinx_ChipTestBoard");
case defs::MATTERHORN:
return std::string("Matterhorn");
default:
return std::string("Unknown");
}
@@ -739,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<double>(f.value);
std::ostringstream os;
switch (unit) {
case defs::FrequencyUnit::Hz:
os << val << "Hz";
break;
case defs::FrequencyUnit::kHz:
os << val / (static_cast<double>(1e3)) << "kHz";
break;
case defs::FrequencyUnit::MHz:
os << val / (static_cast<double>(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;
@@ -756,6 +788,8 @@ template <> defs::detectorType StringTo(const std::string &s) {
return defs::GOTTHARD2;
if (s == "Xilinx_ChipTestBoard")
return defs::XILINX_CHIPTESTBOARD;
if (s == "Matterhorn")
return defs::MATTERHORN;
throw RuntimeError("Unknown detector type " + s);
}
+18
View File
@@ -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<ns> 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<ns>("asvn"));
}
TEST_CASE("string to frequency", "[support]") {
REQUIRE(StringTo<defs::Hz>("150") == defs::Hz(150));
REQUIRE(StringTo<defs::Hz>("150Hz") == defs::Hz(150));
REQUIRE(StringTo<defs::Hz>("1.5kHz") == defs::Hz(1500));
REQUIRE(StringTo<defs::Hz>("1.5MHz") == defs::Hz(1500000));
REQUIRE_THROWS(StringTo<defs::Hz>("5xs"));
REQUIRE_THROWS(StringTo<defs::Hz>("asvn"));
}
TEST_CASE("string to detectorType") {
using dt = slsDetectorDefs::detectorType;
REQUIRE(StringTo<dt>("Eiger") == dt::EIGER);
+6 -3
View File
@@ -257,7 +257,7 @@ def connectToVirtualServers(name, num_mods, ctb_object=False):
counts_sec = 5
while (counts_sec != 0):
try:
d.virtual = [num_mods, SERVER_START_PORTNO]
d.virtual = [num_mods, SERVER_START_PORTNO] # sets the hostnames
break
except Exception as e:
# stop server still not up, wait a bit longer
@@ -288,13 +288,16 @@ def startReceiver(num_mods, fp, no_log_file = False, quiet_mode=False):
def loadConfig(name, rx_hostname = 'localhost', settingsdir = None, log_file_fp = None, num_mods = 1, num_frames = 1, num_interfaces = 1):
Log(LogLevel.INFO, 'Loading config', log_file_fp, True)
try:
d = connectToVirtualServers(name, num_mods)
if name == 'ctb' or name == 'xilinx_ctb':
d = connectToVirtualServers(name, num_mods, ctb_object=True)
else:
d = connectToVirtualServers(name, num_mods)
if name == 'jungfrau' or name == 'moench':
d.numinterfaces = num_interfaces
d.udp_dstport = DEFAULT_UDP_DST_PORTNO
if name == 'eiger' or num_interfaces == 2:
if d.numinterfaces == 2:
d.udp_dstport2 = DEFAULT_UDP_DST_PORTNO + 1
d.rx_hostname = rx_hostname