diff --git a/docs/CMakeLists.txt b/docs/CMakeLists.txt index 41055eee9..62e11f673 100644 --- a/docs/CMakeLists.txt +++ b/docs/CMakeLists.txt @@ -11,7 +11,8 @@ add_executable(gendoc src/gendoc.cpp) # This is a bit hacky, but better than exposing stuff? target_include_directories(gendoc PRIVATE ${PROJECT_SOURCE_DIR}/slsDetectorSoftware/src) target_link_libraries(gendoc PRIVATE - slsDetectorShared + slsDetectorStatic + ) set_target_properties(gendoc PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin diff --git a/python/CMakeLists.txt b/python/CMakeLists.txt index eeac372f0..13e6abb3d 100755 --- a/python/CMakeLists.txt +++ b/python/CMakeLists.txt @@ -12,6 +12,7 @@ pybind11_add_module(_slsdet src/duration.cpp src/DurationWrapper.cpp src/pedestal.cpp + src/bit.cpp ) target_link_libraries(_slsdet PUBLIC diff --git a/python/scripts/generate_functions.py b/python/scripts/generate_functions.py index 5d281cdd9..ab57f740f 100644 --- a/python/scripts/generate_functions.py +++ b/python/scripts/generate_functions.py @@ -8,6 +8,7 @@ to be installed. When the Detector API is updated this file should be run manually. """ +import os from clang import cindex import subprocess import argparse @@ -33,6 +34,24 @@ def green(msg): return f"{GREENC}{msg}{ENDC}" +def find_libclang(): + """Find libclang in the current Conda/Mamba environment.""" + conda_prefix = os.environ.get("CONDA_PREFIX") + if conda_prefix: + lib_dir = os.path.join(conda_prefix, "lib") + # Look for libclang*.so files + for f in os.listdir(lib_dir): + if f.startswith("libclang") and f.endswith(".so"): + return os.path.join(lib_dir, f) + + # fallback: system-wide search + path = ctypes.util.find_library("clang") + if path: + return path + + raise FileNotFoundError("libclang not found in CONDA_PREFIX or system paths.") + + def check_libclang_version(required="12"): # Use already-loaded libclang, or let cindex resolve it lib = ctypes.CDLL(cindex.Config.library_file or ctypes.util.find_library("clang")) @@ -201,7 +220,9 @@ if __name__ == "__main__": action="store_true", ) cargs = parser.parse_args() - + + libclang_path = find_libclang() + cindex.Config.set_library_file(libclang_path) check_libclang_version("12") check_clang_format_version(12) check_for_compile_commands_json(cargs.build_path) diff --git a/python/slsdet/__init__.py b/python/slsdet/__init__.py index 7cfbd17fb..7af732cef 100755 --- a/python/slsdet/__init__.py +++ b/python/slsdet/__init__.py @@ -27,6 +27,9 @@ from .defines import * IpAddr = _slsdet.IpAddr MacAddr = _slsdet.MacAddr +RegisterAddress = _slsdet.RegisterAddress +BitAddress = _slsdet.BitAddress +RegisterValue = _slsdet.RegisterValue scanParameters = _slsdet.scanParameters currentSrcParameters = _slsdet.currentSrcParameters DurationWrapper = _slsdet.DurationWrapper diff --git a/python/slsdet/detector.py b/python/slsdet/detector.py index 36d9a13bd..14170c5d3 100755 --- a/python/slsdet/detector.py +++ b/python/slsdet/detector.py @@ -3,6 +3,7 @@ from ._slsdet import CppDetectorApi from ._slsdet import slsDetectorDefs from ._slsdet import IpAddr, MacAddr +from ._slsdet import RegisterAddress, RegisterValue, BitAddress runStatus = slsDetectorDefs.runStatus timingMode = slsDetectorDefs.timingMode @@ -1813,6 +1814,148 @@ class Detector(CppDetectorApi): [Eiger] Address is +0x100 for only left, +0x200 for only right. """ return self._register + + def define_reg(self, *, name: str, addr): + """ + [Ctb] Define a name for a register to be used later with reg. + + Example + -------- + + d.define_reg('myreg',addr=0x6) + d.define_reg('myreg',addr=RegisterAddress(0x6))') + """ + if isinstance(addr, int): + addr = RegisterAddress(addr) + elif not isinstance(addr, RegisterAddress): + raise ValueError("addr must int or RegisterAddress") + self.setRegisterDefinition(name, addr) + + + def define_bit(self, *, name: str, addr, bit_position:int=None): + """ + [Ctb] Define a name for a bit in a register to be used later with setBit/clearBit/getBit + + Example + -------- + + bit1 = BitAddress(RegisterAddress(0x6),7) + d.define_bit('mybit',addr=bit1) + d.define_bit('mybit',addr=0x6, bit=7) + d.define_bit('mybit',addr=RegisterAddress(0x6), bit=7) + d.define_bit('mybit',addr='myreg', bit=7) #if myreg defined before + """ + + # bitAddress + if isinstance(addr, BitAddress): + if bit_position is not None: + raise ValueError("If addr is BitAddress, bit_position must be None") + bitaddr = addr + # register name/address + bit_position + else: + if isinstance(addr, str): + addr = self.getRegisterAddress(addr) + elif isinstance(addr, int): + addr = RegisterAddress(addr) + elif not isinstance(addr, RegisterAddress): + raise ValueError("addr must be str, int or RegisterAddress") + + if bit_position is None: + raise ValueError("bit_position must be provided if addr is used.") + if not isinstance(bit_position, int): + raise ValueError("bit_position must be int") + + bitaddr = BitAddress(addr, bit_position) + + self.setBitDefinition(name, bitaddr) + + def _resolve_bit_name_or_addr(self, bitname_or_addr, bit_position=None): + """ + Internal function to resolve bit name or address arguments for setBit, clearBit and getBit + Returns a BitAddress + """ + #Old usage passing two ints or [RegisterAddress and int] + if isinstance(bitname_or_addr, (int, RegisterAddress)): + if bit_position is None: + raise ValueError("bit_position must be provided when passing int address") + if not isinstance(bit_position, int): + raise ValueError("bit_position must be int") + return BitAddress(bitname_or_addr, bit_position) + + # New usage with str or BitAddress + # str + if isinstance(bitname_or_addr, str): + bitname_or_addr = self.getBitAddress(bitname_or_addr) + + if bit_position is not None: + raise ValueError("bit_position must be None when passing str or BitAddress") + + #must now be a BitAddress + if not isinstance(bitname_or_addr, BitAddress): + raise ValueError("bitname_or_addr must be str, BitAddress, int or RegisterAddress") + + return bitname_or_addr + + + def setBit(self, bitname_or_addr, bit_position=None): + """ + Set a bit in a register + [Ctb] Can use a named bit address + + Example + -------- + d.setBit(0x5, 3) + d.setBit(RegisterAddress(0x5), 3) + + #Ctb + d.setBit('mybit') + + myreg = RegisterAddress(0x5) + mybit = BitAddress(myreg, 5) + d.setBit(mybit) + """ + resolved = self._resolve_bit_name_or_addr(bitname_or_addr, bit_position) + return super().setBit(resolved) + + def clearBit(self, bitname_or_addr, bit_position=None): + """ + Clear a bit in a register + [Ctb] Can use a named bit address + + Example + -------- + d.clearBit(0x5, 3) + + #Ctb + d.clearBit('mybit') + + myreg = RegisterAddress(0x5) + mybit = BitAddress(myreg, 5) + d.clearBit(mybit) + """ + resolved = self._resolve_bit_name_or_addr(bitname_or_addr, bit_position) + return super().clearBit(resolved) + + @element + def getBit(self, bitname_or_addr, bit_position=None): + """ + Get a bit from a register + [Ctb] Can use a named bit address + + Example + -------- + d.getBit(0x5, 3) + + #Ctb + d.getBit('mybit') + + myreg = RegisterAddress(0x5) + mybit = BitAddress(myreg, 5) + d.getBit(mybit) + """ + resolved = self._resolve_bit_name_or_addr(bitname_or_addr, bit_position) + return super().getBit(resolved) + @property def slowadc(self): diff --git a/python/slsdet/registers.py b/python/slsdet/registers.py index 4c80585e9..7cad52d16 100755 --- a/python/slsdet/registers.py +++ b/python/slsdet/registers.py @@ -1,13 +1,30 @@ # SPDX-License-Identifier: LGPL-3.0-or-other # Copyright (C) 2021 Contributors to the SLS Detector Package + +from ._slsdet import RegisterValue, RegisterAddress +from .utils import element + class Register: def __init__(self, detector): self._detector = detector + @element def __getitem__(self, key): + if isinstance(key, str): + key = self._detector.getRegisterAddress(key) + elif isinstance(key, int): + key = RegisterAddress(key) return self._detector.readRegister(key) def __setitem__(self, key, value): + if isinstance(key, str): + key = self._detector.getRegisterAddress(key) + elif isinstance(key, int): + key = RegisterAddress(key) + + if isinstance(value, int): + value = RegisterValue(value) + self._detector.writeRegister(key, value, False) class Adc_register: diff --git a/python/slsdet/utils.py b/python/slsdet/utils.py index 9181298e5..4039119d4 100755 --- a/python/slsdet/utils.py +++ b/python/slsdet/utils.py @@ -141,20 +141,19 @@ def make_ip(arg): def make_mac(arg): return _make(arg, _slsdet.MacAddr) - def make_path(arg): return _make(arg, Path) def _make(arg, transform): - """Helper function for make_mac and make_ip special cases for + """Helper function for make_mac, make_ip and other special cases for dict, list and tuple. Otherwise just calls transform""" if isinstance(arg, dict): - return {key: transform(value) for key, value in arg.items()} + return {key: _make(value, transform) for key, value in arg.items()} elif isinstance(arg, list): - return [transform(a) for a in arg] + return [_make(a, transform) for a in arg] elif isinstance(arg, tuple): - return tuple(transform(a) for a in arg) + return tuple(_make(a, transform) for a in arg) else: return transform(arg) diff --git a/python/src/bit.cpp b/python/src/bit.cpp new file mode 100644 index 000000000..498319f51 --- /dev/null +++ b/python/src/bit.cpp @@ -0,0 +1,67 @@ +// SPDX-License-Identifier: LGPL-3.0-or-other +// Copyright (C) 2021 Contributors to the SLS Detector Package +/* +This file contains Python bindings for the RegisterAddr, BitAddress and +RegisterValue classes. +*/ +#include "py_headers.h" +#include "sls/bit_utils.h" + +namespace py = pybind11; + +using sls::BitAddress; +using sls::RegisterAddress; +using sls::RegisterValue; + +void init_bit(py::module &m) { + + py::class_(m, "RegisterAddress") + .def(py::init()) + .def(py::init()) + .def(py::init()) + .def("__repr__", + [](const RegisterAddress &addr) { + return "RegisterAddress(" + addr.str() + ")"; + }) + .def("__str__", &RegisterAddress::str) + .def("value", &RegisterAddress::value) + .def(py::self == py::self) + .def(py::self != py::self); + + py::class_(m, "BitAddress") + .def(py::init()) + .def(py::init()) + .def("__repr__", + [](const BitAddress &addr) { + return "BitAddress(" + addr.str() + ")"; + }) + .def("__str__", &BitAddress::str) + .def("address", &BitAddress::address) + .def("bitPosition", &BitAddress::bitPosition) + .def(py::self == py::self) + .def(py::self != py::self); + + py::class_(m, "RegisterValue") + .def(py::init<>()) + .def(py::init()) + .def(py::init()) + .def("__repr__", + [](const RegisterValue &val) { + return "RegisterValue(" + val.str() + ")"; + }) + .def("__str__", &RegisterValue::str) + .def("value", &RegisterValue::value) + .def(py::self == py::self) + .def(py::self != py::self) + .def("__or__", [](const RegisterValue &lhs, + const RegisterValue &rhs) { return lhs | rhs; }) + .def("__or__", + [](const RegisterValue &lhs, uint32_t rhs) { return lhs | rhs; }) + .def( + "__ior__", + [](RegisterValue &lhs, uint32_t rhs) -> RegisterValue & { + lhs |= rhs; + return lhs; + }, + py::return_value_policy::reference_internal); +} diff --git a/python/src/detector.cpp b/python/src/detector.cpp index c0fedc1b1..070dac493 100644 --- a/python/src/detector.cpp +++ b/python/src/detector.cpp @@ -8,6 +8,7 @@ #include "sls/Detector.h" #include "sls/TimeHelper.h" #include "sls/ToString.h" +#include "sls/bit_utils.h" #include "sls/network_utils.h" #include "sls/sls_detector_defs.h" @@ -15,10 +16,13 @@ #include namespace py = pybind11; void init_det(py::module &m) { + using sls::BitAddress; using sls::defs; using sls::Detector; using sls::ns; using sls::Positions; + using sls::RegisterAddress; + using sls::RegisterValue; using sls::Result; m.def("freeSharedMemory", @@ -942,7 +946,6 @@ void init_det(py::module &m) { (void (Detector::*)(const std::vector &)) & Detector::setRxROI, py::arg()); - CppDetectorApi.def("clearRxROI", (void (Detector::*)()) & Detector::clearRxROI); CppDetectorApi.def( @@ -1796,6 +1799,82 @@ void init_det(py::module &m) { (std::string(Detector::*)(const defs::dacIndex) const) & Detector::getSlowADCName, py::arg()); + CppDetectorApi.def("getRegisterDefinitionsCount", + (int (Detector::*)() const) & + Detector::getRegisterDefinitionsCount); + CppDetectorApi.def( + "setRegisterDefinition", + (void (Detector::*)(const std::string &, sls::RegisterAddress)) & + Detector::setRegisterDefinition, + py::arg(), py::arg()); + CppDetectorApi.def("hasRegisterDefinition", + (bool (Detector::*)(const std::string &) const) & + Detector::hasRegisterDefinition, + py::arg()); + CppDetectorApi.def("hasRegisterDefinition", + (bool (Detector::*)(sls::RegisterAddress) const) & + Detector::hasRegisterDefinition, + py::arg()); + CppDetectorApi.def( + "getRegisterAddress", + (sls::RegisterAddress(Detector::*)(const std::string &) const) & + Detector::getRegisterAddress, + py::arg()); + CppDetectorApi.def("getRegisterName", + (std::string(Detector::*)(sls::RegisterAddress) const) & + Detector::getRegisterName, + py::arg()); + CppDetectorApi.def("clearRegisterDefinitions", + (void (Detector::*)()) & + Detector::clearRegisterDefinitions); + CppDetectorApi.def( + "setRegisterDefinitions", + (void (Detector::*)(const std::map &)) & + Detector::setRegisterDefinitions, + py::arg()); + CppDetectorApi.def( + "getRegisterDefinitions", + (std::map(Detector::*)() const) & + Detector::getRegisterDefinitions); + CppDetectorApi.def("getBitDefinitionsCount", + (int (Detector::*)() const) & + Detector::getBitDefinitionsCount); + CppDetectorApi.def( + "setBitDefinition", + (void (Detector::*)(const std::string &, sls::BitAddress)) & + Detector::setBitDefinition, + py::arg(), py::arg()); + CppDetectorApi.def("hasBitDefinition", + (bool (Detector::*)(const std::string &) const) & + Detector::hasBitDefinition, + py::arg()); + CppDetectorApi.def("hasBitDefinition", + (bool (Detector::*)(sls::BitAddress) const) & + Detector::hasBitDefinition, + py::arg()); + CppDetectorApi.def("toRegisterNameBitString", + (std::string(Detector::*)(sls::BitAddress) const) & + Detector::toRegisterNameBitString, + py::arg()); + CppDetectorApi.def( + "getBitAddress", + (sls::BitAddress(Detector::*)(const std::string &) const) & + Detector::getBitAddress, + py::arg()); + CppDetectorApi.def("getBitName", + (std::string(Detector::*)(sls::BitAddress) const) & + Detector::getBitName, + py::arg()); + CppDetectorApi.def("clearBitDefinitions", + (void (Detector::*)()) & Detector::clearBitDefinitions); + CppDetectorApi.def( + "setBitDefinitions", + (void (Detector::*)(const std::map &)) & + Detector::setBitDefinitions, + py::arg()); + CppDetectorApi.def("getBitDefinitions", (std::map( + Detector::*)() const) & + Detector::getBitDefinitions); CppDetectorApi.def("configureTransceiver", (void (Detector::*)(sls::Positions)) & Detector::configureTransceiver, @@ -1969,6 +2048,58 @@ void init_det(py::module &m) { (void (Detector::*)(const bool, sls::Positions)) & Detector::setUpdateMode, py::arg(), py::arg() = Positions{}); + CppDetectorApi.def("readRegister", + (Result(Detector::*)( + sls::RegisterAddress, sls::Positions) const) & + Detector::readRegister, + py::arg(), py::arg() = Positions{}); + CppDetectorApi.def( + "writeRegister", + (void (Detector::*)(sls::RegisterAddress, sls::RegisterValue, bool, + sls::Positions)) & + Detector::writeRegister, + py::arg(), py::arg(), py::arg() = false, py::arg() = Positions{}); + CppDetectorApi.def( + "setBit", + (void (Detector::*)(sls::BitAddress, bool, sls::Positions)) & + Detector::setBit, + py::arg(), py::arg() = false, py::arg() = Positions{}); + CppDetectorApi.def( + "clearBit", + (void (Detector::*)(sls::BitAddress, bool, sls::Positions)) & + Detector::clearBit, + py::arg(), py::arg() = false, py::arg() = Positions{}); + CppDetectorApi.def( + "getBit", + (Result(Detector::*)(sls::BitAddress, sls::Positions) const) & + Detector::getBit, + py::arg(), py::arg() = Positions{}); + CppDetectorApi.def("readRegister", + (Result(Detector::*)( + const std::string &, sls::Positions) const) & + Detector::readRegister, + py::arg(), py::arg() = Positions{}); + CppDetectorApi.def( + "writeRegister", + (void (Detector::*)(const std::string &, sls::RegisterValue, bool, + sls::Positions)) & + Detector::writeRegister, + py::arg(), py::arg(), py::arg() = false, py::arg() = Positions{}); + CppDetectorApi.def( + "setBit", + (void (Detector::*)(const std::string &, bool, sls::Positions)) & + Detector::setBit, + py::arg(), py::arg() = false, py::arg() = Positions{}); + CppDetectorApi.def( + "clearBit", + (void (Detector::*)(const std::string &, bool, sls::Positions)) & + Detector::clearBit, + py::arg(), py::arg() = false, py::arg() = Positions{}); + CppDetectorApi.def( + "getBit", + (Result(Detector::*)(const std::string &, sls::Positions) const) & + Detector::getBit, + py::arg(), py::arg() = Positions{}); CppDetectorApi.def( "readRegister", (Result(Detector::*)(uint32_t, sls::Positions) const) & @@ -1991,7 +2122,7 @@ void init_det(py::module &m) { py::arg(), py::arg(), py::arg() = false, py::arg() = Positions{}); CppDetectorApi.def( "getBit", - (Result(Detector::*)(uint32_t, int, sls::Positions)) & + (Result(Detector::*)(uint32_t, int, sls::Positions) const) & Detector::getBit, py::arg(), py::arg(), py::arg() = Positions{}); CppDetectorApi.def("executeFirmwareTest", diff --git a/python/src/detector_in.cpp b/python/src/detector_in.cpp index 2c7d4440f..47e5a7e72 100644 --- a/python/src/detector_in.cpp +++ b/python/src/detector_in.cpp @@ -7,15 +7,19 @@ #include "sls/network_utils.h" #include "sls/sls_detector_defs.h" #include "sls/TimeHelper.h" +#include "sls/bit_utils.h" #include #include namespace py = pybind11; void init_det(py::module &m) { + using sls::BitAddress; using sls::defs; using sls::Detector; using sls::ns; using sls::Positions; + using sls::RegisterAddress; + using sls::RegisterValue; using sls::Result; m.def("freeSharedMemory", (void (*)(const int, const int)) &sls::freeSharedMemory, py::arg() = 0, py::arg() = -1); diff --git a/python/src/main.cpp b/python/src/main.cpp index 901c4900e..214f2b81c 100644 --- a/python/src/main.cpp +++ b/python/src/main.cpp @@ -20,6 +20,7 @@ void init_scan(py::module &); void init_source(py::module &); void init_duration(py::module &); void init_pedestal(py::module &); +void init_bit(py::module &); PYBIND11_MODULE(_slsdet, m) { m.doc() = R"pbdoc( @@ -40,6 +41,7 @@ PYBIND11_MODULE(_slsdet, m) { init_source(m); init_duration(m); init_pedestal(m); + init_bit(m); // init_experimental(m); py::module io = m.def_submodule("io", "Submodule for io"); diff --git a/python/tests/test_CtbAPI.py b/python/tests/test_CtbAPI.py new file mode 100644 index 000000000..b82c5a4c7 --- /dev/null +++ b/python/tests/test_CtbAPI.py @@ -0,0 +1,385 @@ +''' +cd python/tests +Specific test: pytest -s -x test_CtbAPI.py::test_define_bit #-x=abort on first failure +Specific test with specific server: pytest -s -x test_CtbAPI.py::test_define_reg[ctb] + +''' + +import pytest, sys, traceback + +from pathlib import Path +current_dir = Path(__file__).resolve().parents[2] +scripts_dir = current_dir / "tests" / "scripts" +sys.path.append(str(scripts_dir)) +print(sys.path) + +from utils_for_test import ( + Log, + LogLevel, + cleanup, + startDetectorVirtualServer, + connectToVirtualServers, + SERVER_START_PORTNO, +) + +from slsdet import Detector, detectorType + + +@pytest.fixture( + scope="session", + params=['ctb', 'xilinx_ctb', 'mythen3'] +) +def simulator(request): + """Fixture to start the detector server once and clean up at the end.""" + det_name = request.param + num_mods = 1 + fp = sys.stdout + + # set up: once per server + Log(LogLevel.INFOBLUE, f'---- {det_name} ----') + cleanup(fp) + startDetectorVirtualServer(det_name, num_mods, fp) + + Log(LogLevel.INFOBLUE, f'Waiting for server to start up and connect') + connectToVirtualServers(det_name, num_mods) + + yield det_name # tests run here + + cleanup(fp) + + +@pytest.mark.withdetectorsimulators +def test_define_reg(simulator, request): + """ Test setting define_reg for ctb and xilinx_ctb.""" + det_name = simulator + from slsdet import RegisterAddress + + d = Detector() + d.hostname = f"localhost:{SERVER_START_PORTNO}" + + if det_name in ['ctb', 'xilinx_ctb']: + prev_reg_defs = d.getRegisterDefinitions() + prev_bit_defs = d.getBitDefinitions() + d.clearRegisterDefinitions() + d.clearBitDefinitions() + + addr1 = RegisterAddress(0x201) + addr2 = RegisterAddress(0x202) + d.define_reg(name="test_reg", addr=RegisterAddress(0x200)) # valid + d.define_reg(name="test_reg", addr=addr1) # takes a register address + d.define_reg(name="test_reg2", addr=0x202) # takes an int + + # not using keyword arguments + with pytest.raises(TypeError) as exc_info: + d.define_reg("randomreg", 0x203) + + # invalid value type + with pytest.raises(Exception) as exc_info: + d.define_reg(name="test_reg3", addr='0x203') + assert "addr must int or RegisterAddress" in str(exc_info.value) + + # defining with duplicate value + with pytest.raises(Exception) as exc_info: + d.define_reg(name="test_reg3", addr=addr1) + assert "Value already assigned" in str(exc_info.value) + + assert(d.getRegisterAddress("test_reg") == addr1) + assert(d.getRegisterName(addr1) == "test_reg") + + # accessing non existent reg name + with pytest.raises(Exception) as exc_info: + d.reg['random_reg'] + assert "No entry found for key" in str(exc_info.value) + + # get non existing reg address + with pytest.raises(Exception) as exc_info: + d.getRegisterName(RegisterAddress(0x300)) + assert "No entry found for value" in str(exc_info.value) + + d.clearRegisterDefinitions() + + d.setRegisterDefinitions(prev_reg_defs) + d.setBitDefinitions(prev_bit_defs) + + else: + with pytest.raises(Exception) as exc_info: + d.define_reg(name="test_reg", addr=0x201) + assert "Register Definitions only for CTB" in str(exc_info.value) + + Log(LogLevel.INFOGREEN, f"✅ {request.node.name} passed") + + +@pytest.mark.withdetectorsimulators +def test_define_bit(simulator, request): + """ Test setting define_bit for ctb and xilinx_ctb.""" + det_name = simulator + from slsdet import RegisterAddress, BitAddress + + # setup + d = Detector() + d.hostname = f"localhost:{SERVER_START_PORTNO}" + + if det_name in ['ctb', 'xilinx_ctb']: + prev_reg_defs = d.getRegisterDefinitions() + prev_bit_defs = d.getBitDefinitions() + d.clearRegisterDefinitions() + d.clearBitDefinitions() + + addr1 = RegisterAddress(0x201) + addr2 = RegisterAddress(0x202) + d.define_reg(name="test_reg1", addr=addr1) + d.define_reg(name="test_reg2", addr=addr2) + + # not using keyword arguments + with pytest.raises(TypeError) as exc_info: + d.define_bit("randombit", 0x203, 1) + + # invalid value type (bit=string) + with pytest.raises(ValueError) as exc_info: + d.define_bit(name="test_bit1", addr='test_reg1', bit_position='1') + + # invalid bit_position + with pytest.raises(Exception) as exc_info: + d.define_bit(name="test_bit1", addr='test_reg1', bit_position=32) + assert "Bit position must be between 0 and 31" in str(exc_info.value) + + # defining with random reg value + with pytest.raises(Exception) as exc_info: + d.define_bit(name='test_bit1', addr='random_reg', bit_position=1) + assert "No entry found for key" in str(exc_info.value) + + bit1 = BitAddress(addr1, 2) + bit2 = BitAddress(addr1, 4) + bit3 = BitAddress(addr2, 3) + + # defining bit address with bit_position as well + with pytest.raises(ValueError) as exc_info: + d.define_bit(name='test_bit1', addr=bit1, bit_position=1) + assert "bit_position must be None" in str(exc_info.value) + + + d.define_bit(name="test_bit1", addr='test_reg2', bit_position=1) + d.define_bit(name="test_bit1", addr='test_reg1', bit_position=1) # modify reg + d.define_bit(name='test_bit1', addr=bit1) # modify pos + d.define_bit(name="test_bit2", addr=0x201, bit_position=4) # int addr + d.define_bit(name="test_bit3", addr=addr2, bit_position=3) # RegisterAddress addr + + + assert(d.getBitAddress('test_bit1') == bit1) + assert(d.getBitAddress('test_bit2') == bit2) + assert(d.getBitAddress('test_bit3') == bit3) + assert(d.getBitAddress('test_bit1').address() == addr1) + assert(d.getBitAddress('test_bit1').bitPosition() == 2) + assert(d.getBitAddress('test_bit2') == BitAddress(addr1, 4)) + + assert(d.getBitName(bit1) == 'test_bit1') + assert(d.getBitName(bit2) == 'test_bit2') + assert(d.getBitName(bit3) == 'test_bit3') + assert(d.getBitName(BitAddress(addr2,3)) == 'test_bit3') + + # bit doesnt exist for that reg + with pytest.raises(Exception) as exc_info: + d.getBitName(BitAddress(addr1, 5)) + assert "No entry found for value" in str(exc_info.value) + + # addr doesnt exist for that reg + with pytest.raises(Exception) as exc_info: + d.getBitName(BitAddress(RegisterAddress(0x300), 5)) + assert "No entry found for value" in str(exc_info.value) + + d.clearRegisterDefinitions() + d.clearBitDefinitions() + + d.setRegisterDefinitions(prev_reg_defs) + d.setBitDefinitions(prev_bit_defs) + else: + with pytest.raises(Exception) as exc_info: + d.define_bit(name="test_bit", addr=0x300, bit_position=1) + assert "Bit Definitions only for CTB" in str(exc_info.value) + + + Log(LogLevel.INFOGREEN, f"✅ {request.node.name} passed") + + +@pytest.mark.withdetectorsimulators +def test_using_defined_reg_and_bit(simulator, request): + """ Test using defined reg and bit define_bit for ctb and xilinx_ctb.""" + det_name = simulator + from slsdet import RegisterAddress, BitAddress, RegisterValue + + # setup + d = Detector() + d.hostname = f"localhost:{SERVER_START_PORTNO}" + + if det_name in ['ctb', 'xilinx_ctb']: + prev_reg_defs = d.getRegisterDefinitions() + prev_bit_defs = d.getBitDefinitions() + d.clearRegisterDefinitions() + d.clearBitDefinitions() + + addr1 = RegisterAddress(0x201) + addr2 = RegisterAddress(0x202) + d.setRegisterDefinition('test_reg1', addr1) + d.setRegisterDefinition('test_reg2', addr2) + bit1 = BitAddress(addr1, 2) + bit2 = BitAddress(addr1, 4) + bit3 = BitAddress(addr2, 3) + d.setBitDefinition('test_bit1', bit1) + d.setBitDefinition('test_bit2', bit2) + d.setBitDefinition('test_bit3', bit3) + + prev_val_addr1 = d.reg[addr1] + prev_val_addr2 = d.reg[addr2] + + # reg name doesnt exist + with pytest.raises(Exception) as exc_info: + d.reg['random_reg'] + assert "No entry found for key" in str(exc_info.value) + with pytest.raises(Exception) as exc_info: + d.setBit('random_reg') + assert "No entry found for key" in str(exc_info.value) + with pytest.raises(Exception) as exc_info: + d.clearBit('random_reg') + assert "No entry found for key" in str(exc_info.value) + with pytest.raises(Exception) as exc_info: + d.getBit('random_reg') + assert "No entry found for key" in str(exc_info.value) + + # bit name doesnt exist + with pytest.raises(Exception) as exc_info: + d.setBit('test_bit1', bit_position=5) + assert "bit_position must be None" in str(exc_info.value) + with pytest.raises(Exception) as exc_info: + d.clearBit('test_bit1', bit_position=5) + assert "bit_position must be None" in str(exc_info.value) + with pytest.raises(Exception) as exc_info: + d.getBit('test_bit1', bit_position=5) + assert "bit_position must be None" in str(exc_info.value) + + d.reg['test_reg1'] = RegisterValue(0x0) + assert(d.reg['test_reg1'].value() == 0x0) + + d.reg['test_reg1'] = RegisterValue(0x10) + assert(d.reg['test_reg1'].value() == 0x10) + + d.setBit('test_bit1') + assert(d.reg['test_reg1'].value() == 0x14) # 0x10 | (1 << 2) + + d.clearBit('test_bit1') + assert(d.reg['test_reg1'].value() == 0x10) + + assert(d.getBit('test_bit1') == 0) + + # restore previous values + d.reg[addr1] = prev_val_addr1 + d.reg[addr2] = prev_val_addr2 + + d.clearRegisterDefinitions() + d.clearBitDefinitions() + + d.setRegisterDefinitions(prev_reg_defs) + d.setBitDefinitions(prev_bit_defs) + else: + with pytest.raises(Exception) as exc_info: + d.define_bit(name="test_bit", addr=0x300, bit_position=1) + assert "Bit Definitions only for CTB" in str(exc_info.value) + + Log(LogLevel.INFOGREEN, f"✅ {request.node.name} passed") + + +@pytest.mark.withdetectorsimulators +def test_definelist_reg(simulator, request): + """ Test using definelist_reg for ctb and xilinx_ctb.""" + det_name = simulator + from slsdet import RegisterAddress, BitAddress, RegisterValue + + # setup + d = Detector() + d.hostname = f"localhost:{SERVER_START_PORTNO}" + + if det_name in ['ctb', 'xilinx_ctb']: + prev_reg_defs = d.getRegisterDefinitions() + prev_bit_defs = d.getBitDefinitions() + d.clearRegisterDefinitions() + d.clearBitDefinitions() + + addr1 = RegisterAddress(0x201) + addr2 = RegisterAddress(0x202) + bit1 = BitAddress(addr1, 2) + bit2 = BitAddress(addr1, 4) + bit3 = BitAddress(addr2, 3) + + d.setRegisterDefinitions({ + 'test_reg1': RegisterAddress(0x201), + 'test_reg2': RegisterAddress(0x202) + }) + + res = d.getRegisterDefinitions() + assert(res['test_reg1'] == addr1) + assert(res['test_reg2'] == addr2) + assert(len(res) == 2) + + d.clearRegisterDefinitions() + d.clearBitDefinitions() + + d.setRegisterDefinitions(prev_reg_defs) + d.setBitDefinitions(prev_bit_defs) + else: + with pytest.raises(Exception) as exc_info: + d.define_bit(name="test_bit", addr=0x300, bit_position=1) + assert "Bit Definitions only for CTB" in str(exc_info.value) + + Log(LogLevel.INFOGREEN, f"✅ {request.node.name} passed") + + +@pytest.mark.withdetectorsimulators +def test_definelist_bit(simulator, request): + """ Test using definelist_bit for ctb and xilinx_ctb.""" + det_name = simulator + from slsdet import RegisterAddress, BitAddress, RegisterValue + + # setup + d = Detector() + d.hostname = f"localhost:{SERVER_START_PORTNO}" + + if det_name in ['ctb', 'xilinx_ctb']: + prev_reg_defs = d.getRegisterDefinitions() + prev_bit_defs = d.getBitDefinitions() + d.clearRegisterDefinitions() + d.clearBitDefinitions() + + addr1 = RegisterAddress(0x201) + addr2 = RegisterAddress(0x202) + bit1 = BitAddress(addr1, 2) + bit2 = BitAddress(addr1, 4) + bit3 = BitAddress(addr2, 3) + + d.setRegisterDefinitions({ + 'test_reg1': RegisterAddress(0x201), + 'test_reg2': RegisterAddress(0x202) + }) + d.setBitDefinitions({ + 'test_bit1': BitAddress(addr1, 2), + 'test_bit2': BitAddress(addr1, 4), + 'test_bit3': BitAddress(addr2, 3) + }) + + res = d.getBitDefinitions() + assert(len(res) == 3) + assert(res['test_bit1'] == bit1) + assert(res['test_bit2'] == bit2) + assert(res['test_bit3'] == bit3) + assert(res['test_bit2'].address() == addr1) + assert(res['test_bit2'].bitPosition() == 4) + + d.clearRegisterDefinitions() + d.clearBitDefinitions() + + d.setRegisterDefinitions(prev_reg_defs) + d.setBitDefinitions(prev_bit_defs) + else: + with pytest.raises(Exception) as exc_info: + d.define_bit(name="test_bit", addr=0x300, bit_position=1) + assert "Bit Definitions only for CTB" in str(exc_info.value) + + Log(LogLevel.INFOGREEN, f"✅ {request.node.name} passed") \ No newline at end of file diff --git a/python/tests/test_utils.py b/python/tests/test_utils.py index 309ffa9a2..719379235 100755 --- a/python/tests/test_utils.py +++ b/python/tests/test_utils.py @@ -8,7 +8,7 @@ Testing functions from utils.py import pytest from slsdet.utils import * -from slsdet import IpAddr, MacAddr, DurationWrapper +from slsdet import IpAddr, MacAddr, DurationWrapper, RegisterAddress, RegisterValue, BitAddress import datetime as dt import pathlib from pathlib import Path @@ -199,6 +199,7 @@ def test_make_mac_from_tuple(): MacAddr("84:a9:3e:24:32:aa")) + def test_make_path_from_str(): assert make_path("/") == Path("/") assert make_path("/home") == Path("/home") diff --git a/sample/CMakeLists.txt b/sample/CMakeLists.txt index 732bd31cd..e1238106d 100644 --- a/sample/CMakeLists.txt +++ b/sample/CMakeLists.txt @@ -4,12 +4,20 @@ add_executable(using_logger using_logger.cpp) target_link_libraries(using_logger slsSupportShared ) - set_target_properties(using_logger PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin ) +add_executable(using_registers using_registers.cpp) +target_link_libraries(using_registers + slsDetectorShared +) +set_target_properties(using_registers PROPERTIES + RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin +) + + # add_executable(result useResult.cpp) # target_link_libraries(result # slsDetectorShared diff --git a/sample/using_logger.cpp b/sample/using_logger.cpp index 7557d5c83..0019ca327 100644 --- a/sample/using_logger.cpp +++ b/sample/using_logger.cpp @@ -3,15 +3,23 @@ #include "sls/logger.h" #include #include + +using sls::logINFO; +using sls::logINFORED; +using sls::logINFOBLUE; +using sls::logINFOGREEN; +using sls::logERROR; +using sls::logWARNING; + + int main() { //compare old and new std::cout << "Compare output between old and new:\n"; LOG(logINFO) << "Some info message"; LOG(logERROR) << "This is an error"; - LOG(logWARNING) << "While this is only a warning"; prefix="/afs/psi.ch/project/sls_det_software/dhanya_softwareDevelopment/mySoft/slsDetectorPackage/" - p=${file#"$prefix"} - + LOG(logWARNING) << "While this is only a warning"; + //Logging level can be configure at runtime std::cout << "\n\n"; std::cout << "The default macro controlled level is: " diff --git a/sample/using_registers.cpp b/sample/using_registers.cpp new file mode 100644 index 000000000..e3a2f44ff --- /dev/null +++ b/sample/using_registers.cpp @@ -0,0 +1,49 @@ +// SPDX-License-Identifier: LGPL-3.0-or-other +// Copyright (C) 2021 Contributors to the SLS Detector Package + +/* This example assumes that you have a ctb configured or using the virtual ctb detector server*/ + +#include "sls/Detector.h" +#include "sls/bit_utils.h" +#include + + +void somefunc(uint32_t addr){ + std::cout << "somefunc called with: " << addr << std::endl; +} + +int main(){ + + // Config file has the following defines + // define addr somereg 0x5 + // define bit mybit somereg 7 + + sls::Detector d; + auto somereg = d.getRegisterDefinition("somereg"); + d.writeRegister(somereg, sls::RegisterValue(0)); + auto val = d.readRegister(somereg); + + std::cout << "somereg has the address: " << somereg << " and value " << val.squash() << std::endl; + + + auto mybit = d.getBitDefinition("mybit"); + std::cout << "mybit refers to register: " << mybit.address() << " bit nr: " << mybit.bitPosition() << std::endl; + d.setBit(mybit); + val = d.readRegister(somereg); + std::cout << "somereg has the address: " << somereg << " and value " << val.squash() << std::endl; + std::cout << "mybit: " << d.getBit(mybit) << std::endl; + + + //Let's define a bit + sls::BitAddress newbit(sls::RegisterAddress(0x6), 4); + d.setBitDefinition("newbit", newbit); + //This can now be usef from command line "g getbit newbit" + + + + + uint32_t addr = somereg; //I'm not sure this should compile + somefunc(somereg); //This should also not compile + + +} \ No newline at end of file diff --git a/slsDetectorSoftware/generator/Caller.in.h b/slsDetectorSoftware/generator/Caller.in.h index 17ca1e3ef..14dfb22d6 100644 --- a/slsDetectorSoftware/generator/Caller.in.h +++ b/slsDetectorSoftware/generator/Caller.in.h @@ -74,6 +74,24 @@ class Caller { static void EmptyDataCallBack(detectorData *data, uint64_t frameIndex, uint32_t subFrameIndex, void *this_pointer); + std::string bitoperations(int action); + + // parsing from args + // parse from string to RegisterAddress + RegisterAddress parseRegisterAddress(const std::string &addr) const; + // parse from 2 strings to BitAddress + BitAddress parseBitAddress(const std::string &addr, + const std::string &bitPos) const; + // parse from string to RegisterValue + RegisterValue parseRegisterValue(const std::string &addr) const; + // parse validate flag from args and remove it from args + bool parseValidate(); + + // parses from args, but also gets addresses from shared memory if + // applicable + RegisterAddress getRegisterAddress(const std::string &saddr) const; + BitAddress getBitAddress() const; + FunctionMap functions{ {"list", &Caller::list}, diff --git a/slsDetectorSoftware/generator/autocomplete/bash_autocomplete.sh b/slsDetectorSoftware/generator/autocomplete/bash_autocomplete.sh index 5fe099a7d..bcadb4a01 100644 --- a/slsDetectorSoftware/generator/autocomplete/bash_autocomplete.sh +++ b/slsDetectorSoftware/generator/autocomplete/bash_autocomplete.sh @@ -80,7 +80,7 @@ _sd() { local IS_PATH=0 -local SLS_COMMANDS=" acquire activate adcclk adcenable adcenable10g adcindex adcinvert adclist adcname adcphase adcpipeline adcreg adcvpp apulse asamples autocompdisable badchannels blockingtrigger burstmode burstperiod bursts burstsl bustest cdsgain chipversion clearbit clearbusy clientversion clkdiv clkfreq clkphase collectionmode column compdisabletime confadc config configtransceiver counters currentsource dac dacindex daclist dacname dacvalues datastream dbitclk dbitphase dbitpipeline defaultdac defaultpattern delay delayl detectorserverversion detsize diodelay dpulse dr drlist dsamples execcommand exptime exptime1 exptime2 exptime3 extrastoragecells extsampling extsamplingsrc extsig fformat filtercells filterresistor findex firmwaretest firmwareversion fliprows flowcontrol10g fmaster fname foverwrite fpath framecounter frames framesl frametime free fwrite gaincaps gainmode gappixels gatedelay gatedelay1 gatedelay2 gatedelay3 gates getbit hardwareversion highvoltage hostname im_a im_b im_c im_d im_io imagetest initialchecks inj_ch interpolation interruptsubframe kernelversion lastclient led lock master maxadcphaseshift maxclkphaseshift maxdbitphaseshift measuredperiod measuredsubperiod moduleid nextframenumber nmod numinterfaces overflow packageversion parallel parameters partialreset patfname patioctrl patlimits patloop patloop0 patloop1 patloop2 patmask patnloop patnloop0 patnloop1 patnloop2 patsetbit pattern patternstart patwait patwait0 patwait1 patwait2 patwaittime patwaittime0 patwaittime1 patwaittime2 patword pedestalmode period periodl polarity port powerchip powerindex powerlist powername powervalues programfpga pulse pulsechip pulsenmove pumpprobe quad ratecorr readnrows readout readoutspeed readoutspeedlist rebootcontroller reg resetdacs resetfpga romode row runclk runtime rx_arping rx_clearroi rx_dbitlist rx_dbitoffset rx_dbitreorder rx_discardpolicy rx_fifodepth rx_frameindex rx_framescaught rx_framesperfile rx_hostname rx_jsonaddheader rx_jsonpara rx_lastclient rx_lock rx_missingpackets rx_padding rx_printconfig rx_realudpsocksize rx_roi rx_silent rx_start rx_status rx_stop rx_tcpport rx_threads rx_udpsocksize rx_version rx_zmqfreq rx_zmqhwm rx_zmqip rx_zmqport rx_zmqstartfnum rx_zmqstream samples savepattern scan scanerrmsg selinterface serialnumber setbit settings settingslist settingspath signalindex signallist signalname sleep slowadc slowadcindex slowadclist slowadcname slowadcvalues start status stop stopport storagecell_delay storagecell_start subdeadtime subexptime sync syncclk temp_10ge temp_adc temp_control temp_dcdc temp_event temp_fpga temp_fpgaext temp_fpgafl temp_fpgafr temp_slowadc temp_sodl temp_sodr temp_threshold templist tempvalues tengiga threshold thresholdnotb timing timing_info_decoder timinglist timingsource top transceiverenable trigger triggers triggersl trimbits trimen trimval tsamples txdelay txdelay_frame txdelay_left txdelay_right type udp_cleardst udp_dstip udp_dstip2 udp_dstlist udp_dstmac udp_dstmac2 udp_dstport udp_dstport2 udp_firstdst udp_numdst udp_reconfigure udp_srcip udp_srcip2 udp_srcmac udp_srcmac2 udp_validate update updatedetectorserver updatekernel updatemode user v_a v_b v_c v_chip v_d v_io v_limit vchip_comp_adc vchip_comp_fe vchip_cs vchip_opa_1st vchip_opa_fd vchip_ref_comp_fe versions veto vetoalg vetofile vetophoton vetoref vetostream virtual vm_a vm_b vm_c vm_d vm_io zmqhwm zmqip zmqport " +local SLS_COMMANDS=" acquire activate adcclk adcenable adcenable10g adcindex adcinvert adclist adcname adcphase adcpipeline adcreg adcvpp apulse asamples autocompdisable badchannels blockingtrigger burstmode burstperiod bursts burstsl bustest cdsgain chipversion clearbit clearbusy clientversion clkdiv clkfreq clkphase collectionmode column compdisabletime confadc config configtransceiver counters currentsource dac dacindex daclist dacname dacvalues datastream dbitclk dbitphase dbitpipeline defaultdac defaultpattern define_bit define_reg definelist_bit definelist_reg delay delayl detectorserverversion detsize diodelay dpulse dr drlist dsamples execcommand exptime exptime1 exptime2 exptime3 extrastoragecells extsampling extsamplingsrc extsig fformat filtercells filterresistor findex firmwaretest firmwareversion fliprows flowcontrol10g fmaster fname foverwrite fpath framecounter frames framesl frametime free fwrite gaincaps gainmode gappixels gatedelay gatedelay1 gatedelay2 gatedelay3 gates getbit hardwareversion highvoltage hostname im_a im_b im_c im_d im_io imagetest initialchecks inj_ch interpolation interruptsubframe kernelversion lastclient led lock master maxadcphaseshift maxclkphaseshift maxdbitphaseshift measuredperiod measuredsubperiod moduleid nextframenumber nmod numinterfaces overflow packageversion parallel parameters partialreset patfname patioctrl patlimits patloop patloop0 patloop1 patloop2 patmask patnloop patnloop0 patnloop1 patnloop2 patsetbit pattern patternstart patwait patwait0 patwait1 patwait2 patwaittime patwaittime0 patwaittime1 patwaittime2 patword pedestalmode period periodl polarity port powerchip powerindex powerlist powername powervalues programfpga pulse pulsechip pulsenmove pumpprobe quad ratecorr readnrows readout readoutspeed readoutspeedlist rebootcontroller reg resetdacs resetfpga romode row runclk runtime rx_arping rx_clearroi rx_dbitlist rx_dbitoffset rx_dbitreorder rx_discardpolicy rx_fifodepth rx_frameindex rx_framescaught rx_framesperfile rx_hostname rx_jsonaddheader rx_jsonpara rx_lastclient rx_lock rx_missingpackets rx_padding rx_printconfig rx_realudpsocksize rx_roi rx_silent rx_start rx_status rx_stop rx_tcpport rx_threads rx_udpsocksize rx_version rx_zmqfreq rx_zmqhwm rx_zmqip rx_zmqport rx_zmqstartfnum rx_zmqstream samples savepattern scan scanerrmsg selinterface serialnumber setbit settings settingslist settingspath signalindex signallist signalname sleep slowadc slowadcindex slowadclist slowadcname slowadcvalues start status stop stopport storagecell_delay storagecell_start subdeadtime subexptime sync syncclk temp_10ge temp_adc temp_control temp_dcdc temp_event temp_fpga temp_fpgaext temp_fpgafl temp_fpgafr temp_slowadc temp_sodl temp_sodr temp_threshold templist tempvalues tengiga threshold thresholdnotb timing timing_info_decoder timinglist timingsource top transceiverenable trigger triggers triggersl trimbits trimen trimval tsamples txdelay txdelay_frame txdelay_left txdelay_right type udp_cleardst udp_dstip udp_dstip2 udp_dstlist udp_dstmac udp_dstmac2 udp_dstport udp_dstport2 udp_firstdst udp_numdst udp_reconfigure udp_srcip udp_srcip2 udp_srcmac udp_srcmac2 udp_validate update updatedetectorserver updatekernel updatemode user v_a v_b v_c v_chip v_d v_io v_limit vchip_comp_adc vchip_comp_fe vchip_cs vchip_opa_1st vchip_opa_fd vchip_ref_comp_fe versions veto vetoalg vetofile vetophoton vetoref vetostream virtual vm_a vm_b vm_c vm_d vm_io zmqhwm zmqip zmqport " __acquire() { FCN_RETURN="" return 0 @@ -682,6 +682,54 @@ fi fi return 0 } +__define_bit() { +FCN_RETURN="" +if [[ ${IS_GET} -eq 1 ]]; then +if [[ "${cword}" == "2" ]]; then +FCN_RETURN="" +fi +if [[ "${cword}" == "3" ]]; then +FCN_RETURN="" +fi +fi +if [[ ${IS_GET} -eq 0 ]]; then +if [[ "${cword}" == "2" ]]; then +FCN_RETURN="" +fi +if [[ "${cword}" == "3" ]]; then +FCN_RETURN="" +fi +if [[ "${cword}" == "4" ]]; then +FCN_RETURN="" +fi +fi +return 0 +} +__define_reg() { +FCN_RETURN="" +if [[ ${IS_GET} -eq 1 ]]; then +if [[ "${cword}" == "2" ]]; then +FCN_RETURN="" +fi +fi +if [[ ${IS_GET} -eq 0 ]]; then +if [[ "${cword}" == "2" ]]; then +FCN_RETURN="" +fi +if [[ "${cword}" == "3" ]]; then +FCN_RETURN="" +fi +fi +return 0 +} +__definelist_bit() { +FCN_RETURN="" +return 0 +} +__definelist_reg() { +FCN_RETURN="" +return 0 +} __delay() { FCN_RETURN="" if [[ ${IS_GET} -eq 1 ]]; then diff --git a/slsDetectorSoftware/generator/autocomplete/zsh_autocomplete.sh b/slsDetectorSoftware/generator/autocomplete/zsh_autocomplete.sh index 64598dd2b..28dbae901 100644 --- a/slsDetectorSoftware/generator/autocomplete/zsh_autocomplete.sh +++ b/slsDetectorSoftware/generator/autocomplete/zsh_autocomplete.sh @@ -4,7 +4,7 @@ _sd() { -local SLS_COMMANDS=" acquire activate adcclk adcenable adcenable10g adcindex adcinvert adclist adcname adcphase adcpipeline adcreg adcvpp apulse asamples autocompdisable badchannels blockingtrigger burstmode burstperiod bursts burstsl bustest cdsgain chipversion clearbit clearbusy clientversion clkdiv clkfreq clkphase collectionmode column compdisabletime confadc config configtransceiver counters currentsource dac dacindex daclist dacname dacvalues datastream dbitclk dbitphase dbitpipeline defaultdac defaultpattern delay delayl detectorserverversion detsize diodelay dpulse dr drlist dsamples execcommand exptime exptime1 exptime2 exptime3 extrastoragecells extsampling extsamplingsrc extsig fformat filtercells filterresistor findex firmwaretest firmwareversion fliprows flowcontrol10g fmaster fname foverwrite fpath framecounter frames framesl frametime free fwrite gaincaps gainmode gappixels gatedelay gatedelay1 gatedelay2 gatedelay3 gates getbit hardwareversion highvoltage hostname im_a im_b im_c im_d im_io imagetest initialchecks inj_ch interpolation interruptsubframe kernelversion lastclient led lock master maxadcphaseshift maxclkphaseshift maxdbitphaseshift measuredperiod measuredsubperiod moduleid nextframenumber nmod numinterfaces overflow packageversion parallel parameters partialreset patfname patioctrl patlimits patloop patloop0 patloop1 patloop2 patmask patnloop patnloop0 patnloop1 patnloop2 patsetbit pattern patternstart patwait patwait0 patwait1 patwait2 patwaittime patwaittime0 patwaittime1 patwaittime2 patword pedestalmode period periodl polarity port powerchip powerindex powerlist powername powervalues programfpga pulse pulsechip pulsenmove pumpprobe quad ratecorr readnrows readout readoutspeed readoutspeedlist rebootcontroller reg resetdacs resetfpga romode row runclk runtime rx_arping rx_clearroi rx_dbitlist rx_dbitoffset rx_dbitreorder rx_discardpolicy rx_fifodepth rx_frameindex rx_framescaught rx_framesperfile rx_hostname rx_jsonaddheader rx_jsonpara rx_lastclient rx_lock rx_missingpackets rx_padding rx_printconfig rx_realudpsocksize rx_roi rx_silent rx_start rx_status rx_stop rx_tcpport rx_threads rx_udpsocksize rx_version rx_zmqfreq rx_zmqhwm rx_zmqip rx_zmqport rx_zmqstartfnum rx_zmqstream samples savepattern scan scanerrmsg selinterface serialnumber setbit settings settingslist settingspath signalindex signallist signalname sleep slowadc slowadcindex slowadclist slowadcname slowadcvalues start status stop stopport storagecell_delay storagecell_start subdeadtime subexptime sync syncclk temp_10ge temp_adc temp_control temp_dcdc temp_event temp_fpga temp_fpgaext temp_fpgafl temp_fpgafr temp_slowadc temp_sodl temp_sodr temp_threshold templist tempvalues tengiga threshold thresholdnotb timing timing_info_decoder timinglist timingsource top transceiverenable trigger triggers triggersl trimbits trimen trimval tsamples txdelay txdelay_frame txdelay_left txdelay_right type udp_cleardst udp_dstip udp_dstip2 udp_dstlist udp_dstmac udp_dstmac2 udp_dstport udp_dstport2 udp_firstdst udp_numdst udp_reconfigure udp_srcip udp_srcip2 udp_srcmac udp_srcmac2 udp_validate update updatedetectorserver updatekernel updatemode user v_a v_b v_c v_chip v_d v_io v_limit vchip_comp_adc vchip_comp_fe vchip_cs vchip_opa_1st vchip_opa_fd vchip_ref_comp_fe versions veto vetoalg vetofile vetophoton vetoref vetostream virtual vm_a vm_b vm_c vm_d vm_io zmqhwm zmqip zmqport " +local SLS_COMMANDS=" acquire activate adcclk adcenable adcenable10g adcindex adcinvert adclist adcname adcphase adcpipeline adcreg adcvpp apulse asamples autocompdisable badchannels blockingtrigger burstmode burstperiod bursts burstsl bustest cdsgain chipversion clearbit clearbusy clientversion clkdiv clkfreq clkphase collectionmode column compdisabletime confadc config configtransceiver counters currentsource dac dacindex daclist dacname dacvalues datastream dbitclk dbitphase dbitpipeline defaultdac defaultpattern define_bit define_reg definelist_bit definelist_reg delay delayl detectorserverversion detsize diodelay dpulse dr drlist dsamples execcommand exptime exptime1 exptime2 exptime3 extrastoragecells extsampling extsamplingsrc extsig fformat filtercells filterresistor findex firmwaretest firmwareversion fliprows flowcontrol10g fmaster fname foverwrite fpath framecounter frames framesl frametime free fwrite gaincaps gainmode gappixels gatedelay gatedelay1 gatedelay2 gatedelay3 gates getbit hardwareversion highvoltage hostname im_a im_b im_c im_d im_io imagetest initialchecks inj_ch interpolation interruptsubframe kernelversion lastclient led lock master maxadcphaseshift maxclkphaseshift maxdbitphaseshift measuredperiod measuredsubperiod moduleid nextframenumber nmod numinterfaces overflow packageversion parallel parameters partialreset patfname patioctrl patlimits patloop patloop0 patloop1 patloop2 patmask patnloop patnloop0 patnloop1 patnloop2 patsetbit pattern patternstart patwait patwait0 patwait1 patwait2 patwaittime patwaittime0 patwaittime1 patwaittime2 patword pedestalmode period periodl polarity port powerchip powerindex powerlist powername powervalues programfpga pulse pulsechip pulsenmove pumpprobe quad ratecorr readnrows readout readoutspeed readoutspeedlist rebootcontroller reg resetdacs resetfpga romode row runclk runtime rx_arping rx_clearroi rx_dbitlist rx_dbitoffset rx_dbitreorder rx_discardpolicy rx_fifodepth rx_frameindex rx_framescaught rx_framesperfile rx_hostname rx_jsonaddheader rx_jsonpara rx_lastclient rx_lock rx_missingpackets rx_padding rx_printconfig rx_realudpsocksize rx_roi rx_silent rx_start rx_status rx_stop rx_tcpport rx_threads rx_udpsocksize rx_version rx_zmqfreq rx_zmqhwm rx_zmqip rx_zmqport rx_zmqstartfnum rx_zmqstream samples savepattern scan scanerrmsg selinterface serialnumber setbit settings settingslist settingspath signalindex signallist signalname sleep slowadc slowadcindex slowadclist slowadcname slowadcvalues start status stop stopport storagecell_delay storagecell_start subdeadtime subexptime sync syncclk temp_10ge temp_adc temp_control temp_dcdc temp_event temp_fpga temp_fpgaext temp_fpgafl temp_fpgafr temp_slowadc temp_sodl temp_sodr temp_threshold templist tempvalues tengiga threshold thresholdnotb timing timing_info_decoder timinglist timingsource top transceiverenable trigger triggers triggersl trimbits trimen trimval tsamples txdelay txdelay_frame txdelay_left txdelay_right type udp_cleardst udp_dstip udp_dstip2 udp_dstlist udp_dstmac udp_dstmac2 udp_dstport udp_dstport2 udp_firstdst udp_numdst udp_reconfigure udp_srcip udp_srcip2 udp_srcmac udp_srcmac2 udp_validate update updatedetectorserver updatekernel updatemode user v_a v_b v_c v_chip v_d v_io v_limit vchip_comp_adc vchip_comp_fe vchip_cs vchip_opa_1st vchip_opa_fd vchip_ref_comp_fe versions veto vetoalg vetofile vetophoton vetoref vetostream virtual vm_a vm_b vm_c vm_d vm_io zmqhwm zmqip zmqport " __acquire() { FCN_RETURN="" return 0 @@ -606,6 +606,54 @@ fi fi return 0 } +__define_bit() { +FCN_RETURN="" +if [[ ${IS_GET} -eq 1 ]]; then +if [[ "${cword}" == "2" ]]; then +FCN_RETURN="" +fi +if [[ "${cword}" == "3" ]]; then +FCN_RETURN="" +fi +fi +if [[ ${IS_GET} -eq 0 ]]; then +if [[ "${cword}" == "2" ]]; then +FCN_RETURN="" +fi +if [[ "${cword}" == "3" ]]; then +FCN_RETURN="" +fi +if [[ "${cword}" == "4" ]]; then +FCN_RETURN="" +fi +fi +return 0 +} +__define_reg() { +FCN_RETURN="" +if [[ ${IS_GET} -eq 1 ]]; then +if [[ "${cword}" == "2" ]]; then +FCN_RETURN="" +fi +fi +if [[ ${IS_GET} -eq 0 ]]; then +if [[ "${cword}" == "2" ]]; then +FCN_RETURN="" +fi +if [[ "${cword}" == "3" ]]; then +FCN_RETURN="" +fi +fi +return 0 +} +__definelist_bit() { +FCN_RETURN="" +return 0 +} +__definelist_reg() { +FCN_RETURN="" +return 0 +} __delay() { FCN_RETURN="" if [[ ${IS_GET} -eq 1 ]]; then diff --git a/slsDetectorSoftware/generator/commands.yaml b/slsDetectorSoftware/generator/commands.yaml index 62c6c6931..a2f2a269d 100644 --- a/slsDetectorSoftware/generator/commands.yaml +++ b/slsDetectorSoftware/generator/commands.yaml @@ -2761,6 +2761,90 @@ sleep: - argc: 2 arg_types: [ int, special::time_unit ] +define_reg: + is_description: true + actions: + GET: + argc: 1 + arg_types: [ std::string ] + PUT: + argc: 2 + arg_types: [ std::string, int ] + +define_bit: + is_description: true + actions: + GET: + args: + - argc: 1 + arg_types: [ std::string ] + - argc: 2 + arg_types: [ std::string, int ] + PUT: + argc: 3 + arg_types: [ std::string, std::string, int ] + +definelist_reg: + is_description: true + actions: + GET: + argc: 0 + +definelist_bit: + is_description: true + actions: + GET: + argc: 0 + +reg: + is_description: true + actions: + GET: + argc: 1 + arg_types: [ std::string] + PUT: + args: + - argc: 2 + arg_types: [ uint32_t, uint32_t ] + - argc: 3 + arg_types: [ uint32_t, uint32_t, special::validate ] + + +getbit: + is_description: true + actions: + GET: + args: + - argc: 1 + arg_types: [ std::string ] + - argc: 2 + arg_types: [ std::string, std::string ] + + +setbit: + is_description: true + actions: + PUT: + args: + - argc: 1 + arg_types: [ std::string ] + - argc: 2 + arg_types: [ std::string, std::string ] + - argc: 3 + arg_types: [ std::string, std::string, special::validate ] + +clearbit: + is_description: true + actions: + PUT: + args: + - argc: 1 + arg_types: [ std::string ] + - argc: 2 + arg_types: [ std::string, std::string ] + - argc: 3 + arg_types: [ std::string, std::string, special::validate ] + ################# special commands ########################## @@ -4172,36 +4256,6 @@ update: input_types: [ std::string, std::string ] output: [ '"successful"' ] -reg: - help: "[address] [32 bit value][(optional)--validate]\n\t[Mythen3][Gotthard2] Reads/writes to a 32 bit register in hex. Advanced Function!\n\tGoes to stop server. Hence, can be called while calling blocking acquire().\n\t\t Use --validate to force validation when writing to it.\n\t[Eiger] +0x100 for only left, +0x200 for only right." - actions: - GET: - argc: 1 - require_det_id: true - function: readRegister - input: [ 'args[0]' ] - input_types: [ uint32_t ] - cast_input: [ true ] - output: [ OutStringHex(t) ] - PUT: - require_det_id: true - function: writeRegister - output: [ '"["', 'args[0]', '", "', 'args[1]', '"]"' ] - args: - - argc: 2 - input: [ 'args[0]', 'args[1]', '"0"' ] - input_types: [ uint32_t, uint32_t, bool ] - arg_types: [ uint32_t, uint32_t ] - cast_input: [ true, true, true ] - - argc: 3 - arg_types: [ uint32_t, uint32_t, special::validate ] - exceptions: - - condition: 'args[2] != "--validate"' - message: '"Could not scan third argument. Did you mean --validate?"' - input: [ 'args[0]', 'args[1]', '"1"' ] - input_types: [ uint32_t, uint32_t, bool ] - cast_input: [ true, true, true ] - adcreg: help: "[address] [value]\n\t[Jungfrau][Moench][Ctb] Writes to an adc register in hex. Advanced user Function!" actions: @@ -4214,62 +4268,7 @@ adcreg: cast_input: [ true, true ] output: [ ToString(args) ] -getbit: - help: "[reg address in hex] [bit index]\n\tGets bit in address." - actions: - GET: - argc: 2 - exceptions: - - condition: 'StringTo(args[1]) < 0 || StringTo(args[1]) > 31' - message: '"Bit number out of range: " + args[1]' - require_det_id: true - function: getBit - input: [ 'args[0]', 'args[1]' ] - input_types: [ uint32_t, int ] - cast_input: [ true, true ] - output: [ OutString(t) ] -Setbit: - template: true - actions: - PUT: - require_det_id: true - function: setBit - output: [ '"["', 'args[0]', '", "', 'args[1]', '"]"' ] - args: - - argc: 2 - exceptions: - - condition: 'StringTo(args[1]) < 0 || StringTo(args[1]) > 31' - message: '"Bit number out of range: " + args[1]' - input: [ 'args[0]', 'args[1]', '"0"' ] - input_types: [ uint32_t, int, bool ] - arg_types: [ uint32_t, int ] - cast_input: [ true, true, true ] - - argc: 3 - arg_types: [ uint32_t, int, special::validate ] - exceptions: - - condition: 'StringTo(args[1]) < 0 || StringTo(args[1]) > 31' - message: '"Bit number out of range: " + args[1]' - - condition: 'args[2] != "--validate"' - message: '"Could not scan third argument. Did you mean --validate?"' - input: [ 'args[0]', 'args[1]', '"1"' ] - input_types: [ uint32_t, int, bool ] - cast_input: [ true, true, true ] - - -setbit: - inherit_actions: Setbit - help: "[reg address in hex] [bit index]\n\tSets bit in address.\n\tUse --validate to force validation." - actions: - PUT: - function: setBit - -clearbit: - inherit_actions: Setbit - help: "[reg address in hex] [bit index]\n\tClears bit in address.\n\tUse --validate to force validation." - actions: - PUT: - function: clearBit initialchecks: help: "[0, 1]\n\t[Mythen3][Gotthard2] Enable or disable intial compatibility and other checks at detector start up. It is enabled by default. Must come before 'hostname' command to take effect. Can be used to reprogram fpga when current firmware is incompatible.\n\tAdvanced User function!" diff --git a/slsDetectorSoftware/generator/extended_commands.yaml b/slsDetectorSoftware/generator/extended_commands.yaml index a60a3aa26..72a913f3a 100644 --- a/slsDetectorSoftware/generator/extended_commands.yaml +++ b/slsDetectorSoftware/generator/extended_commands.yaml @@ -1096,74 +1096,49 @@ clearbit: PUT: args: - arg_types: - - uint32_t - - int - argc: 2 - cast_input: - - true - - true - - true + - std::string + argc: 1 + cast_input: [] check_det_id: false convert_det_id: true - exceptions: - - condition: StringTo(args[1]) < 0 || StringTo(args[1]) > 31 - message: '"Bit number out of range: " + args[1]' - function: clearBit - input: - - args[0] - - args[1] - - '"0"' - input_types: - - uint32_t - - int - - bool - output: - - '"["' - - args[0] - - '", "' - - args[1] - - '"]"' - require_det_id: true + function: '' + input: [] + input_types: [] + output: [] + require_det_id: false store_result_in_t: false - arg_types: - - uint32_t - - int - - special::validate - argc: 3 - cast_input: - - true - - true - - true + - std::string + - std::string + argc: 2 + cast_input: [] check_det_id: false convert_det_id: true - exceptions: - - condition: StringTo(args[1]) < 0 || StringTo(args[1]) > 31 - message: '"Bit number out of range: " + args[1]' - - condition: args[2] != "--validate" - message: '"Could not scan third argument. Did you mean --validate?"' - function: clearBit - input: - - args[0] - - args[1] - - '"1"' - input_types: - - uint32_t - - int - - bool - output: - - '"["' - - args[0] - - '", "' - - args[1] - - '"]"' - require_det_id: true + function: '' + input: [] + input_types: [] + output: [] + require_det_id: false + store_result_in_t: false + - arg_types: + - std::string + - std::string + - special::validate + argc: 3 + cast_input: [] + check_det_id: false + convert_det_id: true + function: '' + input: [] + input_types: [] + output: [] + require_det_id: false store_result_in_t: false command_name: clearbit function_alias: clearbit - help: "[reg address in hex] [bit index]\n\tClears bit in address.\n\tUse --validate\ - \ to force validation." + help: '' infer_action: true - template: true + is_description: true clearbusy: actions: PUT: @@ -2500,6 +2475,132 @@ defaultpattern: \ to go back to initial settings." infer_action: true template: true +define_bit: + actions: + GET: + args: + - arg_types: + - std::string + argc: 1 + cast_input: [] + check_det_id: false + convert_det_id: true + function: '' + input: [] + input_types: [] + output: [] + require_det_id: false + store_result_in_t: true + - arg_types: + - std::string + - int + argc: 2 + cast_input: [] + check_det_id: false + convert_det_id: true + function: '' + input: [] + input_types: [] + output: [] + require_det_id: false + store_result_in_t: true + PUT: + args: + - arg_types: + - std::string + - std::string + - int + argc: 3 + cast_input: [] + check_det_id: false + convert_det_id: true + function: '' + input: [] + input_types: [] + output: [] + require_det_id: false + store_result_in_t: false + command_name: define_bit + function_alias: define_bit + help: '' + infer_action: true + is_description: true +define_reg: + actions: + GET: + args: + - arg_types: + - std::string + argc: 1 + cast_input: [] + check_det_id: false + convert_det_id: true + function: '' + input: [] + input_types: [] + output: [] + require_det_id: false + store_result_in_t: true + PUT: + args: + - arg_types: + - std::string + - int + argc: 2 + cast_input: [] + check_det_id: false + convert_det_id: true + function: '' + input: [] + input_types: [] + output: [] + require_det_id: false + store_result_in_t: false + command_name: define_reg + function_alias: define_reg + help: '' + infer_action: true + is_description: true +definelist_bit: + actions: + GET: + args: + - arg_types: [] + argc: 0 + cast_input: [] + check_det_id: false + convert_det_id: true + function: '' + input: [] + input_types: [] + output: [] + require_det_id: false + store_result_in_t: true + command_name: definelist_bit + function_alias: definelist_bit + help: '' + infer_action: true + is_description: true +definelist_reg: + actions: + GET: + args: + - arg_types: [] + argc: 0 + cast_input: [] + check_det_id: false + convert_det_id: true + function: '' + input: [] + input_types: [] + output: [] + require_det_id: false + store_result_in_t: true + command_name: definelist_reg + function_alias: definelist_reg + help: '' + infer_action: true + is_description: true delay: actions: GET: @@ -4706,32 +4807,35 @@ getbit: GET: args: - arg_types: - - uint32_t - - int - argc: 2 - cast_input: - - true - - true + - std::string + argc: 1 + cast_input: [] check_det_id: false convert_det_id: true - exceptions: - - condition: StringTo(args[1]) < 0 || StringTo(args[1]) > 31 - message: '"Bit number out of range: " + args[1]' - function: getBit - input: - - args[0] - - args[1] - input_types: - - uint32_t - - int - output: - - OutString(t) - require_det_id: true + function: '' + input: [] + input_types: [] + output: [] + require_det_id: false + store_result_in_t: true + - arg_types: + - std::string + - std::string + argc: 2 + cast_input: [] + check_det_id: false + convert_det_id: true + function: '' + input: [] + input_types: [] + output: [] + require_det_id: false store_result_in_t: true command_name: getbit function_alias: getbit - help: "[reg address in hex] [bit index]\n\tGets bit in address." + help: '' infer_action: true + is_description: true hardwareversion: actions: GET: @@ -7870,20 +7974,16 @@ reg: GET: args: - arg_types: - - uint32_t + - std::string argc: 1 - cast_input: - - true + cast_input: [] check_det_id: false convert_det_id: true - function: readRegister - input: - - args[0] - input_types: - - uint32_t - output: - - OutStringHex(t) - require_det_id: true + function: '' + input: [] + input_types: [] + output: [] + require_det_id: false store_result_in_t: true PUT: args: @@ -7891,68 +7991,34 @@ reg: - uint32_t - uint32_t argc: 2 - cast_input: - - true - - true - - true + cast_input: [] check_det_id: false convert_det_id: true - function: writeRegister - input: - - args[0] - - args[1] - - '"0"' - input_types: - - uint32_t - - uint32_t - - bool - output: - - '"["' - - args[0] - - '", "' - - args[1] - - '"]"' - require_det_id: true + function: '' + input: [] + input_types: [] + output: [] + require_det_id: false store_result_in_t: false - arg_types: - uint32_t - uint32_t - special::validate argc: 3 - cast_input: - - true - - true - - true + cast_input: [] check_det_id: false convert_det_id: true - exceptions: - - condition: args[2] != "--validate" - message: '"Could not scan third argument. Did you mean --validate?"' - function: writeRegister - input: - - args[0] - - args[1] - - '"1"' - input_types: - - uint32_t - - uint32_t - - bool - output: - - '"["' - - args[0] - - '", "' - - args[1] - - '"]"' - require_det_id: true + function: '' + input: [] + input_types: [] + output: [] + require_det_id: false store_result_in_t: false command_name: reg function_alias: reg - help: "[address] [32 bit value][(optional)--validate]\n\t[Mythen3][Gotthard2] Reads/writes\ - \ to a 32 bit register in hex. Advanced Function!\n\tGoes to stop server. Hence,\ - \ can be called while calling blocking acquire().\n\t\t Use --validate to force\ - \ validation when writing to it.\n\t[Eiger] +0x100 for only left, +0x200 for only\ - \ right." + help: '' infer_action: true + is_description: true resetdacs: actions: PUT: @@ -9577,74 +9643,49 @@ setbit: PUT: args: - arg_types: - - uint32_t - - int - argc: 2 - cast_input: - - true - - true - - true + - std::string + argc: 1 + cast_input: [] check_det_id: false convert_det_id: true - exceptions: - - condition: StringTo(args[1]) < 0 || StringTo(args[1]) > 31 - message: '"Bit number out of range: " + args[1]' - function: setBit - input: - - args[0] - - args[1] - - '"0"' - input_types: - - uint32_t - - int - - bool - output: - - '"["' - - args[0] - - '", "' - - args[1] - - '"]"' - require_det_id: true + function: '' + input: [] + input_types: [] + output: [] + require_det_id: false store_result_in_t: false - arg_types: - - uint32_t - - int - - special::validate - argc: 3 - cast_input: - - true - - true - - true + - std::string + - std::string + argc: 2 + cast_input: [] check_det_id: false convert_det_id: true - exceptions: - - condition: StringTo(args[1]) < 0 || StringTo(args[1]) > 31 - message: '"Bit number out of range: " + args[1]' - - condition: args[2] != "--validate" - message: '"Could not scan third argument. Did you mean --validate?"' - function: setBit - input: - - args[0] - - args[1] - - '"1"' - input_types: - - uint32_t - - int - - bool - output: - - '"["' - - args[0] - - '", "' - - args[1] - - '"]"' - require_det_id: true + function: '' + input: [] + input_types: [] + output: [] + require_det_id: false + store_result_in_t: false + - arg_types: + - std::string + - std::string + - special::validate + argc: 3 + cast_input: [] + check_det_id: false + convert_det_id: true + function: '' + input: [] + input_types: [] + output: [] + require_det_id: false store_result_in_t: false command_name: setbit function_alias: setbit - help: "[reg address in hex] [bit index]\n\tSets bit in address.\n\tUse --validate\ - \ to force validation." + help: '' infer_action: true - template: true + is_description: true settings: actions: GET: diff --git a/slsDetectorSoftware/include/sls/Detector.h b/slsDetectorSoftware/include/sls/Detector.h index 2e70a0540..a200c99c7 100644 --- a/slsDetectorSoftware/include/sls/Detector.h +++ b/slsDetectorSoftware/include/sls/Detector.h @@ -3,6 +3,7 @@ #pragma once #include "sls/Pattern.h" #include "sls/Result.h" +#include "sls/bit_utils.h" #include "sls/network_utils.h" #include "sls/sls_detector_defs.h" #include @@ -1837,6 +1838,64 @@ class Detector { /** [CTB][Xilinx CTB] */ std::string getSlowADCName(const defs::dacIndex i) const; + /** [CTB][Xilinx CTB] */ + int getRegisterDefinitionsCount() const; + + /** [CTB][Xilinx CTB] */ + void setRegisterDefinition(const std::string &name, RegisterAddress addr); + + /** [CTB][Xilinx CTB] */ + bool hasRegisterDefinition(const std::string &name) const; + + /** [CTB][Xilinx CTB] */ + bool hasRegisterDefinition(RegisterAddress addr) const; + + /** [CTB][Xilinx CTB] */ + RegisterAddress getRegisterAddress(const std::string &name) const; + + /** [CTB][Xilinx CTB] */ + std::string getRegisterName(RegisterAddress addr) const; + + /** [CTB][Xilinx CTB] */ + void clearRegisterDefinitions(); + + /** [CTB][Xilinx CTB] */ + void + setRegisterDefinitions(const std::map &list); + + /** [CTB][Xilinx CTB] */ + std::map getRegisterDefinitions() const; + + /** [CTB][Xilinx CTB] */ + int getBitDefinitionsCount() const; + + /** [CTB][Xilinx CTB] */ + void setBitDefinition(const std::string &name, BitAddress addr); + + /** [CTB][Xilinx CTB] */ + bool hasBitDefinition(const std::string &name) const; + + /** [CTB][Xilinx CTB] */ + bool hasBitDefinition(BitAddress addr) const; + + /** [CTB][Xilinx CTB] */ + std::string toRegisterNameBitString(BitAddress addr) const; + + /** [CTB][Xilinx CTB] returns bit position and address */ + BitAddress getBitAddress(const std::string &name) const; + + /** [CTB][Xilinx CTB] */ + std::string getBitName(BitAddress addr) const; + + /** [CTB][Xilinx CTB] */ + void clearBitDefinitions(); + + /** [CTB][Xilinx CTB] */ + void setBitDefinitions(const std::map &list); + + /** [CTB][Xilinx CTB] */ + std::map getBitDefinitions() const; + ///@} /** @name Xilinx CTB Specific */ @@ -2045,26 +2104,71 @@ class Detector { /** Advanced user Function! \n * Goes to stop server. Hence, can be called while calling blocking * acquire(). \n [Eiger] Address is +0x100 for only left, +0x200 for only - * right. */ - Result readRegister(uint32_t addr, Positions pos = {}) const; + * right.*/ + Result readRegister(RegisterAddress addr, + Positions pos = {}) const; /** Advanced user Function! \n * Goes to stop server. Hence, can be called while calling blocking * acquire(). \n [Eiger] Address is +0x100 for only left, +0x200 for only - * right. */ - void writeRegister(uint32_t addr, uint32_t val, bool validate = false, - Positions pos = {}); + * right.*/ + void writeRegister(RegisterAddress addr, RegisterValue val, + bool validate = false, Positions pos = {}); - /** Advanced user Function! */ - void setBit(uint32_t addr, int bitnr, bool validate = false, + /** Advanced user Function! */ + void setBit(BitAddress addr, bool validate = false, Positions pos = {}); + + /** Advanced user Function!*/ + void clearBit(BitAddress addr, bool validate = false, Positions pos = {}); + + /** Advanced user Function! */ + Result getBit(BitAddress addr, Positions pos = {}) const; + + /** [CTB][Xilinx CTB] Advanced user Function! */ + Result readRegister(const std::string ®_name, + Positions pos = {}) const; + + /** [CTB][Xilinx CTB] Advanced user Function! */ + void writeRegister(const std::string ®_name, RegisterValue val, + bool validate = false, Positions pos = {}); + + /** [CTB][Xilinx CTB] Advanced user Function! */ + void setBit(const std::string &bit_name, bool validate = false, Positions pos = {}); - /** Advanced user Function! */ - void clearBit(uint32_t addr, int bitnr, bool validate = false, + /** [CTB][Xilinx CTB] Advanced user Function! */ + void clearBit(const std::string &bit_name, bool validate = false, Positions pos = {}); - /** Advanced user Function! */ - Result getBit(uint32_t addr, int bitnr, Positions pos = {}); + /** [CTB][Xilinx CTB] Advanced user Function! */ + Result getBit(const std::string &bit_name, Positions pos = {}) const; + + /** Deprecated Advanced user Function! */ + [[deprecated("Use the overload taking RegisterAddress instead of " + "uint32_t")]] Result + readRegister(uint32_t addr, Positions pos = {}) const; + + /** Deprecated Advanced user Function! */ + [[deprecated("Use the overload taking RegisterAddress and RegisterValue " + "instead of uint32_t")]] void + writeRegister(uint32_t addr, uint32_t val, bool validate = false, + Positions pos = {}); + + /** Deprecated Advanced user Function! */ + [[deprecated("Use the overload taking BitAddress instead of uint32_t and " + "int")]] void + setBit(uint32_t addr, int bitnr, bool validate = false, Positions pos = {}); + + /** Deprecated Advanced user Function! */ + [[deprecated("Use the overload taking BitAddress instead of uint32_t and " + "int")]] void + clearBit(uint32_t addr, int bitnr, bool validate = false, + Positions pos = {}); + + /** Deprecated Advanced user Function! */ + [[deprecated("Use the overload taking BitAddress instead of uint32_t and " + "int")]] Result + getBit(uint32_t addr, int bitnr, Positions pos = {}) const; /** [Jungfrau][Moench][Mythen3][Gotthard2][CTB] Advanced user * Function! */ diff --git a/slsDetectorSoftware/src/Caller.cpp b/slsDetectorSoftware/src/Caller.cpp index 292b881f8..ef6990030 100644 --- a/slsDetectorSoftware/src/Caller.cpp +++ b/slsDetectorSoftware/src/Caller.cpp @@ -1453,100 +1453,6 @@ std::string Caller::chipversion(int action) { return os.str(); } -std::string Caller::clearbit(int action) { - - std::ostringstream os; - // print help - if (action == slsDetectorDefs::HELP_ACTION) { - os << R"V0G0N([reg address in hex] [bit index] - Clears bit in address. - Use --validate to force validation. )V0G0N" - << std::endl; - return os.str(); - } - - // check if action and arguments are valid - if (action == slsDetectorDefs::PUT_ACTION) { - if (1 && args.size() != 2 && args.size() != 3) { - throw RuntimeError("Wrong number of arguments for action PUT"); - } - - if (args.size() == 2) { - try { - StringTo(args[0]); - } catch (...) { - throw RuntimeError("Could not convert argument 0 to uint32_t"); - } - try { - StringTo(args[1]); - } catch (...) { - throw RuntimeError("Could not convert argument 1 to int"); - } - try { - StringTo("0"); - } catch (...) { - throw RuntimeError("Could not convert argument 2 to bool"); - } - } - - if (args.size() == 3) { - try { - StringTo(args[0]); - } catch (...) { - throw RuntimeError("Could not convert argument 0 to uint32_t"); - } - try { - StringTo(args[1]); - } catch (...) { - throw RuntimeError("Could not convert argument 1 to int"); - } - try { - StringTo("1"); - } catch (...) { - throw RuntimeError("Could not convert argument 2 to bool"); - } - } - - } - - else { - - throw RuntimeError( - "INTERNAL ERROR: Invalid action: supported actions are ['PUT']"); - } - - // generate code for each action - if (action == slsDetectorDefs::PUT_ACTION) { - if (args.size() == 2) { - if (StringTo(args[1]) < 0 || StringTo(args[1]) > 31) { - throw RuntimeError("Bit number out of range: " + args[1]); - } - auto arg0 = StringTo(args[0]); - auto arg1 = StringTo(args[1]); - auto arg2 = StringTo("0"); - det->clearBit(arg0, arg1, arg2, std::vector{det_id}); - os << "[" << args[0] << ", " << args[1] << "]" << '\n'; - } - - if (args.size() == 3) { - if (StringTo(args[1]) < 0 || StringTo(args[1]) > 31) { - throw RuntimeError("Bit number out of range: " + args[1]); - } - if (args[2] != "--validate") { - throw RuntimeError( - "Could not scan third argument. Did you mean --validate?"); - } - auto arg0 = StringTo(args[0]); - auto arg1 = StringTo(args[1]); - auto arg2 = StringTo("1"); - det->clearBit(arg0, arg1, arg2, std::vector{det_id}); - os << "[" << args[0] << ", " << args[1] << "]" << '\n'; - } - } - - return os.str(); -} - std::string Caller::clearbusy(int action) { std::ostringstream os; @@ -5955,60 +5861,6 @@ std::string Caller::gates(int action) { return os.str(); } -std::string Caller::getbit(int action) { - - std::ostringstream os; - // print help - if (action == slsDetectorDefs::HELP_ACTION) { - os << R"V0G0N([reg address in hex] [bit index] - Gets bit in address. )V0G0N" - << std::endl; - return os.str(); - } - - // check if action and arguments are valid - if (action == slsDetectorDefs::GET_ACTION) { - if (1 && args.size() != 2) { - throw RuntimeError("Wrong number of arguments for action GET"); - } - - if (args.size() == 2) { - try { - StringTo(args[0]); - } catch (...) { - throw RuntimeError("Could not convert argument 0 to uint32_t"); - } - try { - StringTo(args[1]); - } catch (...) { - throw RuntimeError("Could not convert argument 1 to int"); - } - } - - } - - else { - - throw RuntimeError( - "INTERNAL ERROR: Invalid action: supported actions are ['GET']"); - } - - // generate code for each action - if (action == slsDetectorDefs::GET_ACTION) { - if (args.size() == 2) { - if (StringTo(args[1]) < 0 || StringTo(args[1]) > 31) { - throw RuntimeError("Bit number out of range: " + args[1]); - } - auto arg0 = StringTo(args[0]); - auto arg1 = StringTo(args[1]); - auto t = det->getBit(arg0, arg1, std::vector{det_id}); - os << OutString(t) << '\n'; - } - } - - return os.str(); -} - std::string Caller::hardwareversion(int action) { std::ostringstream os; @@ -8454,7 +8306,7 @@ std::string Caller::patternstart(int action) { // print help if (action == slsDetectorDefs::HELP_ACTION) { os << R"V0G0N( - [Mythen3][Xilinx Ctb] Starts Pattern )V0G0N" + [Mythen3][Ctb][Xilinx Ctb] Starts Pattern )V0G0N" << std::endl; return os.str(); } @@ -10096,119 +9948,6 @@ std::string Caller::rebootcontroller(int action) { return os.str(); } -std::string Caller::reg(int action) { - - std::ostringstream os; - // print help - if (action == slsDetectorDefs::HELP_ACTION) { - os << R"V0G0N([address] [32 bit value][(optional)--validate] - [Mythen3][Gotthard2] Reads/writes to a 32 bit register in hex. Advanced Function! - Goes to stop server. Hence, can be called while calling blocking acquire(). - Use --validate to force validation when writing to it. - [Eiger] +0x100 for only left, +0x200 for only right. )V0G0N" - << std::endl; - return os.str(); - } - - // check if action and arguments are valid - if (action == slsDetectorDefs::GET_ACTION) { - if (1 && args.size() != 1) { - throw RuntimeError("Wrong number of arguments for action GET"); - } - - if (args.size() == 1) { - try { - StringTo(args[0]); - } catch (...) { - throw RuntimeError("Could not convert argument 0 to uint32_t"); - } - } - - } - - else if (action == slsDetectorDefs::PUT_ACTION) { - if (1 && args.size() != 2 && args.size() != 3) { - throw RuntimeError("Wrong number of arguments for action PUT"); - } - - if (args.size() == 2) { - try { - StringTo(args[0]); - } catch (...) { - throw RuntimeError("Could not convert argument 0 to uint32_t"); - } - try { - StringTo(args[1]); - } catch (...) { - throw RuntimeError("Could not convert argument 1 to uint32_t"); - } - try { - StringTo("0"); - } catch (...) { - throw RuntimeError("Could not convert argument 2 to bool"); - } - } - - if (args.size() == 3) { - try { - StringTo(args[0]); - } catch (...) { - throw RuntimeError("Could not convert argument 0 to uint32_t"); - } - try { - StringTo(args[1]); - } catch (...) { - throw RuntimeError("Could not convert argument 1 to uint32_t"); - } - try { - StringTo("1"); - } catch (...) { - throw RuntimeError("Could not convert argument 2 to bool"); - } - } - - } - - else { - - throw RuntimeError("INTERNAL ERROR: Invalid action: supported actions " - "are ['GET', 'PUT']"); - } - - // generate code for each action - if (action == slsDetectorDefs::GET_ACTION) { - if (args.size() == 1) { - auto arg0 = StringTo(args[0]); - auto t = det->readRegister(arg0, std::vector{det_id}); - os << OutStringHex(t) << '\n'; - } - } - - if (action == slsDetectorDefs::PUT_ACTION) { - if (args.size() == 2) { - auto arg0 = StringTo(args[0]); - auto arg1 = StringTo(args[1]); - auto arg2 = StringTo("0"); - det->writeRegister(arg0, arg1, arg2, std::vector{det_id}); - os << "[" << args[0] << ", " << args[1] << "]" << '\n'; - } - - if (args.size() == 3) { - if (args[2] != "--validate") { - throw RuntimeError( - "Could not scan third argument. Did you mean --validate?"); - } - auto arg0 = StringTo(args[0]); - auto arg1 = StringTo(args[1]); - auto arg2 = StringTo("1"); - det->writeRegister(arg0, arg1, arg2, std::vector{det_id}); - os << "[" << args[0] << ", " << args[1] << "]" << '\n'; - } - } - - return os.str(); -} - std::string Caller::resetdacs(int action) { std::ostringstream os; @@ -12384,100 +12123,6 @@ std::string Caller::serialnumber(int action) { return os.str(); } -std::string Caller::setbit(int action) { - - std::ostringstream os; - // print help - if (action == slsDetectorDefs::HELP_ACTION) { - os << R"V0G0N([reg address in hex] [bit index] - Sets bit in address. - Use --validate to force validation. )V0G0N" - << std::endl; - return os.str(); - } - - // check if action and arguments are valid - if (action == slsDetectorDefs::PUT_ACTION) { - if (1 && args.size() != 2 && args.size() != 3) { - throw RuntimeError("Wrong number of arguments for action PUT"); - } - - if (args.size() == 2) { - try { - StringTo(args[0]); - } catch (...) { - throw RuntimeError("Could not convert argument 0 to uint32_t"); - } - try { - StringTo(args[1]); - } catch (...) { - throw RuntimeError("Could not convert argument 1 to int"); - } - try { - StringTo("0"); - } catch (...) { - throw RuntimeError("Could not convert argument 2 to bool"); - } - } - - if (args.size() == 3) { - try { - StringTo(args[0]); - } catch (...) { - throw RuntimeError("Could not convert argument 0 to uint32_t"); - } - try { - StringTo(args[1]); - } catch (...) { - throw RuntimeError("Could not convert argument 1 to int"); - } - try { - StringTo("1"); - } catch (...) { - throw RuntimeError("Could not convert argument 2 to bool"); - } - } - - } - - else { - - throw RuntimeError( - "INTERNAL ERROR: Invalid action: supported actions are ['PUT']"); - } - - // generate code for each action - if (action == slsDetectorDefs::PUT_ACTION) { - if (args.size() == 2) { - if (StringTo(args[1]) < 0 || StringTo(args[1]) > 31) { - throw RuntimeError("Bit number out of range: " + args[1]); - } - auto arg0 = StringTo(args[0]); - auto arg1 = StringTo(args[1]); - auto arg2 = StringTo("0"); - det->setBit(arg0, arg1, arg2, std::vector{det_id}); - os << "[" << args[0] << ", " << args[1] << "]" << '\n'; - } - - if (args.size() == 3) { - if (StringTo(args[1]) < 0 || StringTo(args[1]) > 31) { - throw RuntimeError("Bit number out of range: " + args[1]); - } - if (args[2] != "--validate") { - throw RuntimeError( - "Could not scan third argument. Did you mean --validate?"); - } - auto arg0 = StringTo(args[0]); - auto arg1 = StringTo(args[1]); - auto arg2 = StringTo("1"); - det->setBit(arg0, arg1, arg2, std::vector{det_id}); - os << "[" << args[0] << ", " << args[1] << "]" << '\n'; - } - } - - return os.str(); -} - std::string Caller::settings(int action) { std::ostringstream os; diff --git a/slsDetectorSoftware/src/Caller.h b/slsDetectorSoftware/src/Caller.h index 12a665f79..9211caedb 100644 --- a/slsDetectorSoftware/src/Caller.h +++ b/slsDetectorSoftware/src/Caller.h @@ -107,6 +107,10 @@ class Caller { std::string dbitpipeline(int action); std::string defaultdac(int action); std::string defaultpattern(int action); + std::string define_bit(int action); + std::string define_reg(int action); + std::string definelist_bit(int action); + std::string definelist_reg(int action); std::string delay(int action); std::string delayl(int action); std::string detectorserverversion(int action); @@ -398,6 +402,24 @@ class Caller { static void EmptyDataCallBack(detectorData *data, uint64_t frameIndex, uint32_t subFrameIndex, void *this_pointer); + std::string bitoperations(int action); + + // parsing from args + // parse from string to RegisterAddress + RegisterAddress parseRegisterAddress(const std::string &addr) const; + // parse from 2 strings to BitAddress + BitAddress parseBitAddress(const std::string &addr, + const std::string &bitPos) const; + // parse from string to RegisterValue + RegisterValue parseRegisterValue(const std::string &addr) const; + // parse validate flag from args and remove it from args + bool parseValidate(); + + // parses from args, but also gets addresses from shared memory if + // applicable + RegisterAddress getRegisterAddress(const std::string &saddr) const; + BitAddress getBitAddress() const; + FunctionMap functions{ {"list", &Caller::list}, @@ -451,6 +473,10 @@ class Caller { {"dbitpipeline", &Caller::dbitpipeline}, {"defaultdac", &Caller::defaultdac}, {"defaultpattern", &Caller::defaultpattern}, + {"define_bit", &Caller::define_bit}, + {"define_reg", &Caller::define_reg}, + {"definelist_bit", &Caller::definelist_bit}, + {"definelist_reg", &Caller::definelist_reg}, {"delay", &Caller::delay}, {"delayl", &Caller::delayl}, {"detectorserverversion", &Caller::detectorserverversion}, diff --git a/slsDetectorSoftware/src/CallerSpecial.cpp b/slsDetectorSoftware/src/CallerSpecial.cpp index b21f7332c..7b376ef31 100644 --- a/slsDetectorSoftware/src/CallerSpecial.cpp +++ b/slsDetectorSoftware/src/CallerSpecial.cpp @@ -1437,4 +1437,365 @@ std::string Caller::sleep(int action) { return os.str(); } +std::string Caller::define_reg(int action) { + std::ostringstream os; + if (action == defs::HELP_ACTION) { + os << "[Ctb][Xilinx Ctb]" + "\n\t[reg name] [reg address]" + "\n\n\tSets a user defined register in shared memory. The name " + "can be upto 32 characters long." + "\n\teg." + "\n\tsls_detector_put define_reg test_reg 0x200" + "\n\n\tOne can retrieve the address using the name and vice " + "versa." + "\n\teg." + "\n\tsls_detector_get define_reg test_reg" + "\n\tsls_detector_get define_reg 0x200" + "\n\n\tOne can then use this user-defined name in other commands " + "instead of hard coding the address such as for reg, setbit, " + "clearbit and getbit commands." + "\n\teg." + "\n\tsls_detector_put reg test_reg 0x1" + "\n\tsls_detector_put setbit test_reg 2" + "\n\tsls_detector_put clearbit test_reg 2" + "\n\tsls_detector_get getbit test_reg 2" + << '\n'; + return os.str(); + } + if (det_id != -1) { + throw RuntimeError("Cannot use define at module level. Use the default " + "multi-module level"); + } + if (action == defs::GET_ACTION) { + if (args.size() != 1) { + WrongNumberOfParameters(1); + } + // get name from address + if (is_hex_or_dec_uint(args[0])) { + auto addr = parseRegisterAddress(args[0]); + auto t = det->getRegisterName(addr); + os << t << '\n'; + } + // get address from name + else { + auto t = det->getRegisterAddress(args[0]); + os << t.str() << '\n'; + } + } else if (action == defs::PUT_ACTION) { + if (args.size() != 2) { + WrongNumberOfParameters(2); + } + auto name = args[0]; + auto addr = parseRegisterAddress(args[1]); + det->setRegisterDefinition(name, addr); + os << "addr " << name << ' ' << addr.str() << '\n'; + } else { + throw RuntimeError("Unknown action"); + } + + return os.str(); +} + +std::string Caller::define_bit(int action) { + std::ostringstream os; + if (action == defs::HELP_ACTION) { + os << "[Ctb][Xilinx Ctb]" + "\n\t[bit name] [regiser name/address] [bit position]" + "\n\n\tSets a user defined bit name in shared memory " + "representing the register address and the bit position. The " + "address can be named prior using define_reg command. The name " + "can be upto 32 characters long." + "\n\teg." + "\n\tsls_detector_put define_bit test_bit test_reg 2" + "\n\tsls_detector_put define_bit test_bit 0x200 2" + "\n\n\tOne can retrieve the bit address using the name and vice " + "versa using both register name or address and bit position." + "\n\teg." + "\n\tsls_detector_get define_bit test_bit" + "\n\tsls_detector_get define_bit test_reg 2" + "\n\tsls_detector_get define_bit 0x200 2" + "\n\n\tOne can then use this user-defined name in other commands " + "such as for setbit, clearbit and getbit commands. When using " + "bit names, please dont use register name or address as bit name " + "is already tied to a specific register." + "\n\teg." + "\n\tsls_detector_put setbit test_bit" + "\n\tsls_detector_put clearbit test_bit" + "\n\tsls_detector_get getbit test_bit" + << '\n'; + return os.str(); + } + if (det_id != -1) { + throw RuntimeError("Cannot use define at module level. Use the default " + "multi-module level"); + } + if (action == defs::GET_ACTION) { + // get position from name + if (args.size() == 1) { + auto t = det->getBitAddress(args[0]); + os << det->toRegisterNameBitString(t) << '\n'; + } + // get name from position and address + else if (args.size() == 2) { + auto addr = parseBitAddress(args[0], args[1]); + auto t = det->getBitName(addr); + os << t << '\n'; + + } else { + WrongNumberOfParameters(1); + } + } else if (action == defs::PUT_ACTION) { + if (args.size() != 3) { + WrongNumberOfParameters(3); + } + if (!is_int(args[2])) { + throw RuntimeError("Bit position must be an integer value."); + } + auto name = args[0]; + auto addr = parseBitAddress(args[1], args[2]); + det->setBitDefinition(name, addr); + os << ToString(args) << '\n'; + } else { + throw RuntimeError("Unknown action"); + } + + return os.str(); +} + +std::string Caller::definelist_reg(int action) { + std::ostringstream os; + if (action == defs::HELP_ACTION) { + os << "List of user-defined register definitions in shared memory." + << '\n'; + } else if (action == defs::PUT_ACTION) { + throw RuntimeError("cannot put"); + } else if (action == defs::GET_ACTION) { + if (!args.empty()) { + WrongNumberOfParameters(0); + } + auto t = det->getRegisterDefinitions(); + os << '\n' << ToString(t) << '\n'; + } else { + throw RuntimeError("Unknown action"); + } + return os.str(); +} + +std::string Caller::definelist_bit(int action) { + std::ostringstream os; + if (action == defs::HELP_ACTION) { + os << "List of user-defined bit definitions in shared memory." << '\n'; + } else if (action == defs::PUT_ACTION) { + throw RuntimeError("cannot put"); + } else if (action == defs::GET_ACTION) { + if (!args.empty()) { + WrongNumberOfParameters(0); + } + auto t = det->getBitDefinitions(); + os << "\n["; + for (const auto &[key, val] : t) { + os << key << ": "; + os << det->toRegisterNameBitString(val); + if (&key != &t.rbegin()->first) { + os << ", "; + } + os << '\n'; + } + os << "]\n"; + } else { + throw RuntimeError("Unknown action"); + } + return os.str(); +} + +std::string Caller::reg(int action) { + std::ostringstream os; + if (action == defs::HELP_ACTION) { + os << "[address] [32 bit value][(optional)--validate]" + "\n\tReads/writes to a 32 bit register in hex." + "\n\tAdvanced Function!\n\tGoes to stop server. Hence, can be " + "called while calling blocking acquire()." + "\n\t\t Use --validate to enforce validation when writing to " + "register." + "\n\t[Eiger] +0x100 for only left, +0x200 for only right." + "\n\t[Ctb][Xilinx_Ctb] Address can also be a user-defined name " + "that was set previously using the define command." + "\n\t\teg." + "\n\t\tsls_detector_put reg 0x200 0xFFF --validate" + "\n\t\tsls_detector_get reg test_reg" + "\n\t\tsls_detector_put reg test_reg 0xFF" + << '\n'; + } else { + if (action == defs::PUT_ACTION) { + if (args.size() < 2 || args.size() > 3) { + WrongNumberOfParameters(2); + } + auto validate = parseValidate(); + auto addr = getRegisterAddress(args[0]); + auto val = parseRegisterValue(args[1]); + det->writeRegister(addr, val, validate, std::vector{det_id}); + os << addr.str() << " " << val.str() << '\n'; + } else if (action == defs::GET_ACTION) { + if (args.size() != 1) { + WrongNumberOfParameters(1); + } + auto addr = getRegisterAddress(args[0]); + auto t = det->readRegister(addr, std::vector{det_id}); + os << OutString(t) << '\n'; + } else { + throw RuntimeError("Unknown action"); + } + } + return os.str(); +} + +std::string Caller::getbit(int action) { return bitoperations(action); } + +std::string Caller::setbit(int action) { return bitoperations(action); } + +std::string Caller::clearbit(int action) { return bitoperations(action); } + +std::string Caller::bitoperations(int action) { + std::ostringstream os; + if (action == defs::HELP_ACTION) { + if (cmd == "getbit") { + os << "[reg address in hex] [bit index]\n\tGets bit in address." + << '\n'; + } else if (cmd == "setbit") { + os << "[reg address in hex] [bit index]\n\tSets bit in " + "address.\n\tUse --validate to force validation." + << '\n'; + } else if (cmd == "clearbit") { + os << "[reg address in hex] [bit index]\n\tClears bit in " + "address.\n\tUse --validate to force validation." + << '\n'; + } else { + throw RuntimeError("Unknown command"); + } + os << "\n\t\t[Ctb][Xilinx_Ctb] Address or bit position can also be a " + "user-defined name that was set previously using the define " + "command. When using bit names, avoid register name/ address as " + "the bit name is tied to a specific register already." + "\n\n\teg." + "\n\tsls_detector_get getbit 0x200 2" + "\n\tsls_detector_get getbit test_reg 2" + "\n\tsls_detector_get getbit test_bit" + "\n\tsls_detector_put setbit 0x200 2" + "\n\tsls_detector_put setbit test_reg 2" + "\n\tsls_detector_put setbit test_bit" + "\n\tsls_detector_put clearbit test_bit"; + os << '\n'; + } else { + if (action != defs::GET_ACTION && action != defs::PUT_ACTION) { + throw RuntimeError("Unknown action"); + } + + auto validate = parseValidate(); + auto addr = getBitAddress(); + if (action == defs::GET_ACTION) { + if (cmd == "setbit" || cmd == "clearbit") + throw RuntimeError("Cannot get"); + + auto t = det->getBit(addr, std::vector{det_id}); + os << OutString(t) << '\n'; + } else { + if (cmd == "getbit") + throw RuntimeError("Cannot put"); + if (cmd == "setbit") + det->setBit(addr, validate, std::vector{det_id}); + else if (cmd == "clearbit") + det->clearBit(addr, validate, std::vector{det_id}); + else + throw RuntimeError("Unknown command"); + os << ToString(args) << "\n"; + } + } + return os.str(); +} + +RegisterAddress Caller::parseRegisterAddress(const std::string &addr) const { + try { + return RegisterAddress(StringTo(addr)); + } catch (const std::exception &e) { + throw RuntimeError("Could not parse register address " + addr + + ". Must be an integer value"); + } +} + +BitAddress Caller::parseBitAddress(const std::string &addr, + const std::string &bitPos) const { + auto address = getRegisterAddress(addr); + uint32_t bitPosition = 0; + + // parse bit position + if (!is_hex_or_dec_uint(bitPos)) { + throw RuntimeError("Bit position must be an integer value."); + } + try { + bitPosition = StringTo(bitPos); + } catch (const std::exception &e) { + throw RuntimeError("Could not parse bit position " + bitPos + + ". Must be an integer value"); + } + return BitAddress(address, bitPosition); +} + +RegisterValue Caller::parseRegisterValue(const std::string &addr) const { + try { + return RegisterValue(StringTo(addr)); + } catch (const std::exception &e) { + throw RuntimeError("Could not parse register value " + addr + + ". Must be an integer value"); + } +} + +bool Caller::parseValidate() { + auto it = std::find(args.begin(), args.end(), "--validate"); + bool validate = (it != args.end()); + + // invalid argument (--options), throw + if (!validate) { + auto invalid_it = + std::find_if(args.begin(), args.end(), [](const auto &s) { + // only looks for the first characters + return s.rfind("--", 0) == 0 && s != "--validate"; + }); + if (invalid_it != args.end()) { + throw RuntimeError("Unknown option '" + *invalid_it + + "'. Did you mean '--validate'?"); + } + } + + // --validate should be the last argument (remove it from args) + else { + if (it != args.end() - 1) { + throw RuntimeError("'--validate' should be the last argument."); + } + args.pop_back(); + } + return validate; +} + +RegisterAddress Caller::getRegisterAddress(const std::string &saddr) const { + if (is_hex_or_dec_uint(saddr)) { + return parseRegisterAddress(saddr); + } + return det->getRegisterAddress(saddr); +} + +BitAddress Caller::getBitAddress() const { + int args_size = args.size(); + + // address and bit position + if (args_size == 2) { + return parseBitAddress(args[0], args[1]); + } + + // bit name + if (args_size == 1) { + return det->getBitAddress(args[0]); + } + throw RuntimeError("Invalid number of parameters for bit address."); +} + } // namespace sls \ No newline at end of file diff --git a/slsDetectorSoftware/src/CtbConfig.cpp b/slsDetectorSoftware/src/CtbConfig.cpp index 94f4c10fd..a2452de6f 100644 --- a/slsDetectorSoftware/src/CtbConfig.cpp +++ b/slsDetectorSoftware/src/CtbConfig.cpp @@ -28,214 +28,298 @@ CtbConfig::CtbConfig() { for (size_t i = 0; i != num_slowADCs; ++i) { setSlowADCName(i, "SLOWADC" + ToString(i)); } -} - -void CtbConfig::check_dac_index(size_t i) const { - if (i >= num_dacs) { - std::ostringstream oss; - oss << "Invalid DAC index. Options: 0 - " << num_dacs; - throw RuntimeError(oss.str()); - } -} - -void CtbConfig::check_adc_index(size_t i) const { - if (i >= num_adcs) { - std::ostringstream oss; - oss << "Invalid ADC index. Options: 0 - " << num_adcs; - throw RuntimeError(oss.str()); - } -} - -void CtbConfig::check_signal_index(size_t i) const { - if (i >= num_signals) { - std::ostringstream oss; - oss << "Invalid Signal index. Options: 0 - " << num_signals; - throw RuntimeError(oss.str()); - } -} - -void CtbConfig::check_power_index(size_t i) const { - if (i >= num_powers) { - std::ostringstream oss; - oss << "Invalid Power index. Options: 0 - " << num_powers - << " or V_POWER_A - V_POWER_IO"; - throw RuntimeError(oss.str()); - } -} - -void CtbConfig::check_slow_adc_index(size_t i) const { - if (i >= num_slowADCs) { - std::ostringstream oss; - oss << "Invalid Slow ADC index. Options: 0 - " << num_slowADCs - << " or SLOW_ADC0 - SLOW_ADC7"; - throw RuntimeError(oss.str()); - } -} - -void CtbConfig::check_size(const std::string &name) const { - - if (name.empty()) - throw RuntimeError("Name needs to be at least one character"); - - // name_length -1 to account for \0 termination - if (!(name.size() < (name_length - 1))) { - std::ostringstream oss; - oss << "Length of name needs to be less than " << name_length - 1 - << " chars"; - throw RuntimeError(oss.str()); - } -} - -void CtbConfig::setDacName(size_t index, const std::string &name) { - check_dac_index(index); - check_size(name); - char *dst = &dacnames[index * name_length]; - memset(dst, '\0', name_length); - memcpy(dst, &name[0], name.size()); -} - -void CtbConfig::setDacNames(const std::vector &names) { - if (names.size() != num_dacs) { - throw RuntimeError("Dac names need to be of size " + - std::to_string(num_dacs)); - } - for (size_t i = 0; i != num_dacs; ++i) { - setDacName(i, names[i]); - } -} - -std::string CtbConfig::getDacName(size_t index) const { - check_dac_index(index); - return dacnames + index * name_length; -} - -std::vector CtbConfig::getDacNames() const { - std::vector names; - for (size_t i = 0; i != num_dacs; ++i) - names.push_back(getDacName(i)); - return names; -} - -void CtbConfig::setAdcName(size_t index, const std::string &name) { - check_adc_index(index); - check_size(name); - char *dst = &adcnames[index * name_length]; - memset(dst, '\0', name_length); - memcpy(dst, &name[0], name.size()); -} - -void CtbConfig::setAdcNames(const std::vector &names) { - if (names.size() != num_adcs) { - throw RuntimeError("Adc names need to be of size " + - std::to_string(num_adcs)); - } - for (size_t i = 0; i != num_adcs; ++i) { - setAdcName(i, names[i]); - } -} - -std::string CtbConfig::getAdcName(size_t index) const { - check_adc_index(index); - return adcnames + index * name_length; -} - -std::vector CtbConfig::getAdcNames() const { - std::vector names; - for (size_t i = 0; i != num_adcs; ++i) - names.push_back(getAdcName(i)); - return names; -} - -void CtbConfig::setSignalName(size_t index, const std::string &name) { - check_signal_index(index); - check_size(name); - char *dst = &signalnames[index * name_length]; - memset(dst, '\0', name_length); - memcpy(dst, &name[0], name.size()); -} - -void CtbConfig::setSignalNames(const std::vector &names) { - if (names.size() != num_signals) { - throw RuntimeError("Signal names need to be of size " + - std::to_string(num_signals)); - } - for (size_t i = 0; i != num_signals; ++i) { - setSignalName(i, names[i]); - } -} - -std::string CtbConfig::getSignalName(size_t index) const { - check_signal_index(index); - return signalnames + index * name_length; -} - -std::vector CtbConfig::getSignalNames() const { - std::vector names; - for (size_t i = 0; i != num_signals; ++i) - names.push_back(getSignalName(i)); - return names; -} - -void CtbConfig::setPowerName(size_t index, const std::string &name) { - check_power_index(index); - check_size(name); - char *dst = &powernames[index * name_length]; - memset(dst, '\0', name_length); - memcpy(dst, &name[0], name.size()); -} - -void CtbConfig::setPowerNames(const std::vector &names) { - if (names.size() != num_powers) { - throw RuntimeError("Power names need to be of size " + - std::to_string(num_powers)); - } - for (size_t i = 0; i != num_powers; ++i) { - setPowerName(i, names[i]); - } -} - -std::string CtbConfig::getPowerName(size_t index) const { - check_power_index(index); - return powernames + index * name_length; -} - -std::vector CtbConfig::getPowerNames() const { - std::vector names; - for (size_t i = 0; i != num_powers; ++i) - names.push_back(getPowerName(i)); - return names; -} - -void CtbConfig::setSlowADCName(size_t index, const std::string &name) { - check_slow_adc_index(index); - check_size(name); - char *dst = &slowADCnames[index * name_length]; - memset(dst, '\0', name_length); - memcpy(dst, &name[0], name.size()); -} - -void CtbConfig::setSlowADCNames(const std::vector &names) { - if (names.size() != num_slowADCs) { - throw RuntimeError("Slow ADC names need to be of size " + - std::to_string(num_slowADCs)); - } - for (size_t i = 0; i != num_slowADCs; ++i) { - setSlowADCName(i, names[i]); - } -} - -std::string CtbConfig::getSlowADCName(size_t index) const { - check_slow_adc_index(index); - return slowADCnames + index * name_length; -} - -std::vector CtbConfig::getSlowADCNames() const { - std::vector names; - for (size_t i = 0; i != num_slowADCs; ++i) - names.push_back(getSlowADCName(i)); - return names; + registers.clear(); + bits.clear(); } const char *CtbConfig::shm_tag() { return shm_tag_; } +void CtbConfig::check_index(size_t index, size_t max, const std::string &name, + const std::string &suffix) const { + if (index >= max) { + std::ostringstream oss; + oss << "Invalid " << name << " index. Options: 0 - " << max; + if (!suffix.empty()) { + oss << " " << suffix; + } + throw RuntimeError(oss.str()); + } +} + +void CtbConfig::set_name(const std::string &name, char dst[][name_length], + size_t index) { + if (name.empty()) + throw RuntimeError("Name needs to be at least one character"); + + strcpy_checked(dst[index], name); +} + +void CtbConfig::setNames(const std::vector &names, + size_t expected_size, + void (CtbConfig::*setNameFunc)(size_t, + const std::string &)) { + if (names.size() != expected_size) { + throw RuntimeError("Name list need to be of size " + + std::to_string(expected_size)); + } + for (size_t i = 0; i != expected_size; ++i) { + (this->*setNameFunc)(i, names[i]); + } +} + +std::vector +CtbConfig::getNames(size_t expected_size, + std::string (CtbConfig::*getNameFunc)(size_t) const) const { + std::vector result; + result.reserve(expected_size); + for (size_t i = 0; i != expected_size; ++i) { + result.push_back((this->*getNameFunc)(i)); + } + return result; +} + +void CtbConfig::setDacName(size_t index, const std::string &name) { + check_index(index, num_dacs, "DAC"); + set_name(name, dacnames, index); +} + +void CtbConfig::setDacNames(const std::vector &names) { + setNames(names, num_dacs, &CtbConfig::setDacName); +} + +std::string CtbConfig::getDacName(size_t index) const { + check_index(index, num_dacs, "DAC"); + return dacnames[index]; +} + +std::vector CtbConfig::getDacNames() const { + return getNames(num_dacs, &CtbConfig::getDacName); +} + +void CtbConfig::setAdcName(size_t index, const std::string &name) { + check_index(index, num_adcs, "ADC"); + set_name(name, adcnames, index); +} + +void CtbConfig::setAdcNames(const std::vector &names) { + setNames(names, num_adcs, &CtbConfig::setAdcName); +} + +std::string CtbConfig::getAdcName(size_t index) const { + check_index(index, num_adcs, "ADC"); + return adcnames[index]; +} + +std::vector CtbConfig::getAdcNames() const { + return getNames(num_adcs, &CtbConfig::getAdcName); +} + +void CtbConfig::setSignalName(size_t index, const std::string &name) { + check_index(index, num_signals, "Signal"); + set_name(name, signalnames, index); +} + +void CtbConfig::setSignalNames(const std::vector &names) { + setNames(names, num_signals, &CtbConfig::setSignalName); +} + +std::string CtbConfig::getSignalName(size_t index) const { + check_index(index, num_signals, "Signal"); + return signalnames[index]; +} + +std::vector CtbConfig::getSignalNames() const { + return getNames(num_signals, &CtbConfig::getSignalName); +} + +void CtbConfig::setPowerName(size_t index, const std::string &name) { + check_index(index, num_powers, "Power"); + set_name(name, powernames, index); +} + +void CtbConfig::setPowerNames(const std::vector &names) { + setNames(names, num_powers, &CtbConfig::setPowerName); +} + +std::string CtbConfig::getPowerName(size_t index) const { + check_index(index, num_powers, "Power"); + return powernames[index]; +} + +std::vector CtbConfig::getPowerNames() const { + return getNames(num_powers, &CtbConfig::getPowerName); +} + +void CtbConfig::setSlowADCName(size_t index, const std::string &name) { + check_index(index, num_slowADCs, "Slow ADC", "or SLOW_ADC0 - SLOW_ADC7"); + set_name(name, slowADCnames, index); +} + +void CtbConfig::setSlowADCNames(const std::vector &names) { + setNames(names, num_slowADCs, &CtbConfig::setSlowADCName); +} + +std::string CtbConfig::getSlowADCName(size_t index) const { + check_index(index, num_slowADCs, "Slow ADC", "or SLOW_ADC0 - SLOW_ADC7"); + return slowADCnames[index]; +} + +std::vector CtbConfig::getSlowADCNames() const { + return getNames(num_slowADCs, &CtbConfig::getSlowADCName); +} + +int CtbConfig::getRegisterNamesCount() const { return registers.size(); } + +bool CtbConfig::hasRegisterName(const std::string &name) const { + auto fixed_name = FixedString(name); + return registers.containsKey(fixed_name); +} + +bool CtbConfig::hasRegisterAddress(RegisterAddress addr) const { + return registers.hasValue(addr); +} + +void CtbConfig::clearRegisterNames() { registers.clear(); } + +void CtbConfig::setRegisterName(const std::string &name, RegisterAddress addr) { + try { + auto fixed_name = FixedString(name); + registers.addKeyOrSetValue(fixed_name, addr); + } catch (const std::runtime_error &e) { + std::ostringstream oss; + oss << e.what(); + if (strstr(e.what(), "Maximum capacity reached")) { + oss << ". Clear shared memory and try again."; + } + throw RuntimeError("Could not set register name '" + name + + "': " + oss.str()); + } +} + +RegisterAddress CtbConfig::getRegisterAddress(const std::string &name) const { + try { + auto fixed_name = FixedString(name); + return registers.getValue(fixed_name); + } catch (const std::runtime_error &e) { + throw RuntimeError("Could not get register address for name '" + name + + "': " + std::string(e.what())); + } +} + +std::string CtbConfig::getRegisterName(RegisterAddress addr) const { + try { + return registers.getKey(addr).str(); + } catch (const std::runtime_error &e) { + throw RuntimeError("Could not get register name for address '" + + addr.str() + "': " + std::string(e.what())); + } +} + +void CtbConfig::setRegisterNames( + const std::map &list) { + try { + std::map, RegisterAddress> fixed_list; + for (const auto &[name, value] : list) { + auto fixed_name = FixedString(name); + fixed_list[fixed_name] = value; + } + registers.setMap(fixed_list); + } catch (const std::runtime_error &e) { + throw RuntimeError("Could not set register names: " + + std::string(e.what())); + } +} + +std::map CtbConfig::getRegisterNames() const { + auto fixed_result = registers.getMap(); + std::map result; + for (const auto &[fixed_name, value] : fixed_result) { + result[fixed_name.str()] = value; + } + return result; +} + +int CtbConfig::getBitNamesCount() const { return bits.size(); } + +bool CtbConfig::hasBitName(const std::string &name) const { + auto fixed_name = FixedString(name); + return bits.containsKey(fixed_name); +} + +bool CtbConfig::hasBitAddress(BitAddress addr) const { + return bits.hasValue(addr); +} + +void CtbConfig::clearBitNames() { bits.clear(); } + +void CtbConfig::setBitName(const std::string &name, BitAddress addr) { + try { + auto fixed_name = FixedString(name); + bits.addKeyOrSetValue(fixed_name, addr); + } catch (const std::runtime_error &e) { + std::ostringstream oss; + oss << e.what(); + if (strstr(e.what(), "Maximum capacity reached")) { + oss << ". Clear shared memory and try again."; + } + throw RuntimeError("Could not set bit name '" + name + + "': " + oss.str()); + } +} + +BitAddress CtbConfig::getBitAddress(const std::string &name) const { + try { + auto fixed_name = FixedString(name); + return bits.getValue(fixed_name); + } catch (const std::runtime_error &e) { + throw RuntimeError("Could not get bit address for name '" + name + + "': " + std::string(e.what())); + } +} + +std::string CtbConfig::toRegisterNameBitString(BitAddress addr) const { + std::ostringstream oss; + if (registers.hasValue(addr.address())) { + oss << "[" << registers.getKey(addr.address()).str() << ", " + << std::to_string(addr.bitPosition()) << "]"; + } else { + oss << addr.str(); + } + return oss.str(); +} + +std::string CtbConfig::getBitName(BitAddress addr) const { + try { + return bits.getKey(addr).str(); + } catch (const std::runtime_error &e) { + std::ostringstream oss; + oss << "Could not get bit name for bit address "; + oss << "'" << toRegisterNameBitString(addr) << "'"; + oss << ":" << e.what(); + throw RuntimeError(oss.str()); + } +} + +void CtbConfig::setBitNames(const std::map &list) { + try { + std::map, BitAddress> fixed_list; + for (const auto &[name, value] : list) { + auto fixed_name = FixedString(name); + fixed_list[fixed_name] = value; + } + bits.setMap(fixed_list); + } catch (const std::runtime_error &e) { + throw RuntimeError("Could not set bit names: " + std::string(e.what())); + } +} + +std::map CtbConfig::getBitNames() const { + auto fixed_result = bits.getMap(); + std::map result; + for (const auto &[fixed_name, value] : fixed_result) { + result[fixed_name.str()] = value; + } + return result; +} + } // namespace sls \ No newline at end of file diff --git a/slsDetectorSoftware/src/CtbConfig.h b/slsDetectorSoftware/src/CtbConfig.h index 0e2fe68d7..be5fc66a8 100644 --- a/slsDetectorSoftware/src/CtbConfig.h +++ b/slsDetectorSoftware/src/CtbConfig.h @@ -1,44 +1,57 @@ #pragma once -#include -#include -namespace sls { -#define CTB_SHMAPIVERSION 0x250820 -#define CTB_SHMVERSION 0x250820 +#include "MapOnStack.h" +#include "sls/bit_utils.h" +#include "sls/sls_detector_defs.h" +#include "sls/string_utils.h" + +#include + +namespace sls { class CtbConfig { public: /** fixed pattern */ - int shmversion{CTB_SHMVERSION}; + static constexpr int SHM_VERSION = 0x251215; + int shmversion{SHM_VERSION}; bool isValid{true}; // false if freed to block access from python or c++ api /** end of fixed pattern */ + private: - static constexpr size_t name_length = 20; + static constexpr const char *shm_tag_ = "ctbdacs"; + static constexpr size_t name_length = 32; + static constexpr size_t num_dacs = 18; static constexpr size_t num_adcs = 32; static constexpr size_t num_signals = 64; static constexpr size_t num_powers = 5; static constexpr size_t num_slowADCs = 8; - static constexpr const char *shm_tag_ = "ctbdacs"; - char dacnames[name_length * num_dacs]{}; - char adcnames[name_length * num_adcs]{}; - char signalnames[name_length * num_signals]{}; - char powernames[name_length * num_powers]{}; - char slowADCnames[name_length * num_slowADCs]{}; + char dacnames[num_dacs][name_length]{}; + char adcnames[num_adcs][name_length]{}; + char signalnames[num_signals][name_length]{}; + char powernames[num_powers][name_length]{}; + char slowADCnames[num_slowADCs][name_length]{}; - void check_dac_index(size_t i) const; - void check_adc_index(size_t i) const; - void check_signal_index(size_t i) const; - void check_power_index(size_t i) const; - void check_slow_adc_index(size_t i) const; - void check_size(const std::string &name) const; + void check_index(size_t index, size_t max, const std::string &name, + const std::string &suffix = "") const; + void set_name(const std::string &name, char dst[][name_length], + size_t index); + + void setNames(const std::vector &names, size_t expected_size, + void (CtbConfig::*setNameFunc)(size_t, const std::string &)); + std::vector + getNames(size_t expected_size, + std::string (CtbConfig::*getNameFunc)(size_t) const) const; + + static constexpr size_t Max_Named_Regs = 1024; + static constexpr size_t Max_Named_Bits = 32 * 1024; + MapOnStack, RegisterAddress, Max_Named_Regs, true> + registers; + MapOnStack, BitAddress, Max_Named_Bits, true> bits; public: CtbConfig(); - CtbConfig(const CtbConfig &) = default; - CtbConfig(CtbConfig &&) = default; - CtbConfig &operator=(const CtbConfig &) = default; - ~CtbConfig() = default; + static const char *shm_tag(); void setDacNames(const std::vector &names); void setDacName(size_t index, const std::string &name); @@ -64,7 +77,27 @@ class CtbConfig { void setSlowADCName(size_t index, const std::string &name); std::string getSlowADCName(size_t index) const; std::vector getSlowADCNames() const; - static const char *shm_tag(); + + int getRegisterNamesCount() const; + bool hasRegisterName(const std::string &name) const; + bool hasRegisterAddress(RegisterAddress addr) const; + void clearRegisterNames(); + void setRegisterName(const std::string &name, RegisterAddress addr); + RegisterAddress getRegisterAddress(const std::string &name) const; + std::string getRegisterName(RegisterAddress addr) const; + void setRegisterNames(const std::map &list); + std::map getRegisterNames() const; + + int getBitNamesCount() const; + void clearBitNames(); + bool hasBitName(const std::string &name) const; + bool hasBitAddress(BitAddress addr) const; + std::string toRegisterNameBitString(BitAddress addr) const; + void setBitName(const std::string &name, BitAddress addr); + BitAddress getBitAddress(const std::string &name) const; + std::string getBitName(BitAddress addr) const; + void setBitNames(const std::map &list); + std::map getBitNames() const; }; } // namespace sls diff --git a/slsDetectorSoftware/src/Detector.cpp b/slsDetectorSoftware/src/Detector.cpp index f6dd395af..30d387f92 100644 --- a/slsDetectorSoftware/src/Detector.cpp +++ b/slsDetectorSoftware/src/Detector.cpp @@ -2377,26 +2377,21 @@ void Detector::setLEDEnable(bool enable, Positions pos) { } void Detector::setDacNames(const std::vector names) { - auto dettype = getDetectorType().squash(); - if (dettype != defs::CHIPTESTBOARD && dettype != defs::XILINX_CHIPTESTBOARD) - throw RuntimeError("Named dacs only for CTB"); pimpl->setCtbDacNames(names); } std::vector Detector::getDacNames() const { - std::vector names; - auto type = getDetectorType().squash(); - if (type == defs::CHIPTESTBOARD || type == defs::XILINX_CHIPTESTBOARD) + if (pimpl->isChipTestBoard()) return pimpl->getCtbDacNames(); + std::vector names; for (const auto &index : getDacList()) names.push_back(ToString(index)); return names; } defs::dacIndex Detector::getDacIndex(const std::string &name) const { - auto type = getDetectorType().squash(); - if (type == defs::CHIPTESTBOARD || type == defs::XILINX_CHIPTESTBOARD) { + if (pimpl->isChipTestBoard()) { auto names = getDacNames(); auto it = std::find(names.begin(), names.end(), name); if (it == names.end()) @@ -2407,37 +2402,24 @@ defs::dacIndex Detector::getDacIndex(const std::string &name) const { } void Detector::setDacName(const defs::dacIndex i, const std::string &name) { - auto dettype = getDetectorType().squash(); - if (dettype != defs::CHIPTESTBOARD && dettype != defs::XILINX_CHIPTESTBOARD) - throw RuntimeError("Named dacs only for CTB"); pimpl->setCtbDacName(i, name); } std::string Detector::getDacName(const defs::dacIndex i) const { - auto dettype = getDetectorType().squash(); - if (dettype == defs::CHIPTESTBOARD || dettype == defs::XILINX_CHIPTESTBOARD) + if (pimpl->isChipTestBoard()) return pimpl->getCtbDacName(i); return ToString(i); } void Detector::setAdcNames(const std::vector names) { - auto dettype = getDetectorType().squash(); - if (dettype != defs::CHIPTESTBOARD && dettype != defs::XILINX_CHIPTESTBOARD) - throw RuntimeError("Named adcs only for CTB"); pimpl->setCtbAdcNames(names); } std::vector Detector::getAdcNames() const { - auto dettype = getDetectorType().squash(); - if (dettype != defs::CHIPTESTBOARD && dettype != defs::XILINX_CHIPTESTBOARD) - throw RuntimeError("Named adcs only for CTB"); return pimpl->getCtbAdcNames(); } int Detector::getAdcIndex(const std::string &name) const { - auto dettype = getDetectorType().squash(); - if (dettype != defs::CHIPTESTBOARD && dettype != defs::XILINX_CHIPTESTBOARD) - throw RuntimeError("Named adcs only for CTB"); auto names = getAdcNames(); auto it = std::find(names.begin(), names.end(), name); if (it == names.end()) @@ -2446,37 +2428,22 @@ int Detector::getAdcIndex(const std::string &name) const { } void Detector::setAdcName(const int index, const std::string &name) { - auto dettype = getDetectorType().squash(); - if (dettype != defs::CHIPTESTBOARD && dettype != defs::XILINX_CHIPTESTBOARD) - throw RuntimeError("Named adcs only for CTB"); pimpl->setCtbAdcName(index, name); } std::string Detector::getAdcName(const int i) const { - auto dettype = getDetectorType().squash(); - if (dettype != defs::CHIPTESTBOARD && dettype != defs::XILINX_CHIPTESTBOARD) - throw RuntimeError("Named adcs only for CTB"); return pimpl->getCtbAdcName(i); } void Detector::setSignalNames(const std::vector names) { - auto dettype = getDetectorType().squash(); - if (dettype != defs::CHIPTESTBOARD && dettype != defs::XILINX_CHIPTESTBOARD) - throw RuntimeError("Named signals only for CTB"); pimpl->setCtbSignalNames(names); } std::vector Detector::getSignalNames() const { - auto dettype = getDetectorType().squash(); - if (dettype != defs::CHIPTESTBOARD && dettype != defs::XILINX_CHIPTESTBOARD) - throw RuntimeError("Named signals only for CTB"); return pimpl->getCtbSignalNames(); } int Detector::getSignalIndex(const std::string &name) const { - auto dettype = getDetectorType().squash(); - if (dettype != defs::CHIPTESTBOARD && dettype != defs::XILINX_CHIPTESTBOARD) - throw RuntimeError("Named signals only for CTB"); auto names = getSignalNames(); auto it = std::find(names.begin(), names.end(), name); if (it == names.end()) @@ -2485,38 +2452,22 @@ int Detector::getSignalIndex(const std::string &name) const { } void Detector::setSignalName(const int index, const std::string &name) { - auto dettype = getDetectorType().squash(); - if (dettype != defs::CHIPTESTBOARD && dettype != defs::XILINX_CHIPTESTBOARD) - throw RuntimeError("Named signals only for CTB"); pimpl->setCtbSignalName(index, name); } std::string Detector::getSignalName(const int i) const { - auto dettype = getDetectorType().squash(); - if (dettype != defs::CHIPTESTBOARD && dettype != defs::XILINX_CHIPTESTBOARD) - throw RuntimeError("Named signals only for CTB"); return pimpl->getCtbSignalName(i); } void Detector::setPowerNames(const std::vector names) { - auto dettype = getDetectorType().squash(); - if (getDetectorType().squash() != defs::CHIPTESTBOARD && - dettype != defs::XILINX_CHIPTESTBOARD) - throw RuntimeError("Named powers only for CTB"); pimpl->setCtbPowerNames(names); } std::vector Detector::getPowerNames() const { - auto dettype = getDetectorType().squash(); - if (dettype != defs::CHIPTESTBOARD && dettype != defs::XILINX_CHIPTESTBOARD) - throw RuntimeError("Named powers only for CTB"); return pimpl->getCtbPowerNames(); } defs::dacIndex Detector::getPowerIndex(const std::string &name) const { - auto dettype = getDetectorType().squash(); - if (dettype != defs::CHIPTESTBOARD && dettype != defs::XILINX_CHIPTESTBOARD) - throw RuntimeError("Named powers only for CTB"); auto names = getPowerNames(); auto it = std::find(names.begin(), names.end(), name); if (it == names.end()) @@ -2526,37 +2477,22 @@ defs::dacIndex Detector::getPowerIndex(const std::string &name) const { void Detector::setPowerName(const defs::dacIndex index, const std::string &name) { - auto dettype = getDetectorType().squash(); - if (dettype != defs::CHIPTESTBOARD && dettype != defs::XILINX_CHIPTESTBOARD) - throw RuntimeError("Named powers only for CTB"); pimpl->setCtbPowerName(index, name); } std::string Detector::getPowerName(const defs::dacIndex i) const { - auto dettype = getDetectorType().squash(); - if (dettype != defs::CHIPTESTBOARD && dettype != defs::XILINX_CHIPTESTBOARD) - throw RuntimeError("Named powers only for CTB"); return pimpl->getCtbPowerName(i); } void Detector::setSlowADCNames(const std::vector names) { - auto dettype = getDetectorType().squash(); - if (dettype != defs::CHIPTESTBOARD && dettype != defs::XILINX_CHIPTESTBOARD) - throw RuntimeError("Named SlowADCs only for CTB"); pimpl->setCtbSlowADCNames(names); } std::vector Detector::getSlowADCNames() const { - auto dettype = getDetectorType().squash(); - if (dettype != defs::CHIPTESTBOARD && dettype != defs::XILINX_CHIPTESTBOARD) - throw RuntimeError("Named SlowADCs only for CTB"); return pimpl->getCtbSlowADCNames(); } defs::dacIndex Detector::getSlowADCIndex(const std::string &name) const { - auto dettype = getDetectorType().squash(); - if (dettype != defs::CHIPTESTBOARD && dettype != defs::XILINX_CHIPTESTBOARD) - throw RuntimeError("Named SlowADCs only for CTB"); auto names = getSlowADCNames(); auto it = std::find(names.begin(), names.end(), name); if (it == names.end()) @@ -2566,19 +2502,89 @@ defs::dacIndex Detector::getSlowADCIndex(const std::string &name) const { void Detector::setSlowADCName(const defs::dacIndex index, const std::string &name) { - auto dettype = getDetectorType().squash(); - if (dettype != defs::CHIPTESTBOARD && dettype != defs::XILINX_CHIPTESTBOARD) - throw RuntimeError("Named SlowADCs only for CTB"); pimpl->setCtbSlowADCName(index, name); } std::string Detector::getSlowADCName(const defs::dacIndex i) const { - auto dettype = getDetectorType().squash(); - if (dettype != defs::CHIPTESTBOARD && dettype != defs::XILINX_CHIPTESTBOARD) - throw RuntimeError("Named SlowADCs only for CTB"); return pimpl->getCtbSlowADCName(i); } +int Detector::getRegisterDefinitionsCount() const { + return pimpl->getRegisterDefinitionsCount(); +} + +void Detector::setRegisterDefinition(const std::string &name, + RegisterAddress addr) { + pimpl->setRegisterDefinition(name, addr); +} + +bool Detector::hasRegisterDefinition(const std::string &name) const { + return pimpl->hasRegisterDefinition(name); +} + +bool Detector::hasRegisterDefinition(RegisterAddress addr) const { + return pimpl->hasRegisterDefinition(addr); +} + +RegisterAddress Detector::getRegisterAddress(const std::string &name) const { + return pimpl->getRegisterAddress(name); +} + +std::string Detector::getRegisterName(RegisterAddress addr) const { + return pimpl->getRegisterName(addr); +} + +void Detector::clearRegisterDefinitions() { pimpl->clearRegisterDefinitions(); } + +void Detector::setRegisterDefinitions( + const std::map &list) { + pimpl->setRegisterDefinitions(list); +} + +std::map +Detector::getRegisterDefinitions() const { + return pimpl->getRegisterDefinitions(); +} + +int Detector::getBitDefinitionsCount() const { + return pimpl->getBitDefinitionsCount(); +} + +void Detector::setBitDefinition(const std::string &name, BitAddress addr) { + pimpl->setBitDefinition(name, addr); +} + +bool Detector::hasBitDefinition(const std::string &name) const { + return pimpl->hasBitDefinition(name); +} + +bool Detector::hasBitDefinition(BitAddress addr) const { + return pimpl->hasBitDefinition(addr); +} + +std::string Detector::toRegisterNameBitString(BitAddress addr) const { + return pimpl->toRegisterNameBitString(addr); +} + +BitAddress Detector::getBitAddress(const std::string &name) const { + return pimpl->getBitAddress(name); +} + +std::string Detector::getBitName(BitAddress addr) const { + return pimpl->getBitName(addr); +} + +void Detector::clearBitDefinitions() { pimpl->clearBitDefinitions(); } + +void Detector::setBitDefinitions( + const std::map &list) { + pimpl->setBitDefinitions(list); +} + +std::map Detector::getBitDefinitions() const { + return pimpl->getBitDefinitions(); +} + // Xilinx Ctb Specific void Detector::configureTransceiver(Positions pos) { @@ -2782,26 +2788,78 @@ void Detector::setUpdateMode(const bool updatemode, Positions pos) { } } +Result Detector::readRegister(RegisterAddress addr, + Positions pos) const { + return pimpl->readRegister(addr, pos); +} + +void Detector::writeRegister(RegisterAddress addr, RegisterValue val, + bool validate, Positions pos) { + pimpl->writeRegister(addr, val, validate, pos); +} + +void Detector::setBit(BitAddress addr, bool validate, Positions pos) { + pimpl->setBit(addr, validate, pos); +} + +void Detector::clearBit(BitAddress addr, bool validate, Positions pos) { + pimpl->clearBit(addr, validate, pos); +} + +Result Detector::getBit(BitAddress addr, Positions pos) const { + return pimpl->getBit(addr, pos); +} + +Result Detector::readRegister(const std::string ®_name, + Positions pos) const { + return pimpl->readRegister(reg_name, pos); +} + +void Detector::writeRegister(const std::string ®_name, RegisterValue val, + bool validate, Positions pos) { + pimpl->writeRegister(reg_name, val, validate, pos); +} + +void Detector::setBit(const std::string &bit_name, bool validate, + Positions pos) { + pimpl->setBit(bit_name, validate, pos); +} + +void Detector::clearBit(const std::string &bit_name, bool validate, + Positions pos) { + pimpl->clearBit(bit_name, validate, pos); +} + +Result Detector::getBit(const std::string &bit_name, Positions pos) const { + return pimpl->getBit(bit_name, pos); +} + Result Detector::readRegister(uint32_t addr, Positions pos) const { - return pimpl->Parallel(&Module::readRegister, pos, addr); + auto t = pimpl->readRegister(RegisterAddress(addr), pos); + Result res; + for (const auto &val : t) { + res.push_back(val.value()); + } + return res; } void Detector::writeRegister(uint32_t addr, uint32_t val, bool validate, Positions pos) { - pimpl->Parallel(&Module::writeRegister, pos, addr, val, validate); + pimpl->writeRegister(RegisterAddress(addr), RegisterValue(val), validate, + pos); } void Detector::setBit(uint32_t addr, int bitnr, bool validate, Positions pos) { - pimpl->Parallel(&Module::setBit, pos, addr, bitnr, validate); + pimpl->setBit(BitAddress(RegisterAddress(addr), bitnr), validate, pos); } void Detector::clearBit(uint32_t addr, int bitnr, bool validate, Positions pos) { - pimpl->Parallel(&Module::clearBit, pos, addr, bitnr, validate); + pimpl->clearBit(BitAddress(RegisterAddress(addr), bitnr), validate, pos); } -Result Detector::getBit(uint32_t addr, int bitnr, Positions pos) { - return pimpl->Parallel(&Module::getBit, pos, addr, bitnr); +Result Detector::getBit(uint32_t addr, int bitnr, Positions pos) const { + return pimpl->getBit(BitAddress(RegisterAddress(addr), bitnr), pos); } void Detector::executeFirmwareTest(Positions pos) { diff --git a/slsDetectorSoftware/src/DetectorImpl.cpp b/slsDetectorSoftware/src/DetectorImpl.cpp index fceba4cb8..300396547 100644 --- a/slsDetectorSoftware/src/DetectorImpl.cpp +++ b/slsDetectorSoftware/src/DetectorImpl.cpp @@ -80,10 +80,10 @@ void DetectorImpl::initSharedMemory() { } if (ctb_shm.exists()) { ctb_shm.openSharedMemory(true); - if (ctb_shm()->shmversion != CTB_SHMVERSION) { + if (ctb_shm()->shmversion != CtbConfig::SHM_VERSION) { LOG(logERROR) << "CTB shared memory version mismatch (expected 0x" - << std::hex << CTB_SHMVERSION << " but got 0x" + << std::hex << CtbConfig::SHM_VERSION << " but got 0x" << ctb_shm()->shmversion << std::dec << ". Free Shared memory to continue."; ctb_shm.unmapSharedMemory(); @@ -1935,86 +1935,317 @@ void DetectorImpl::setBadChannels(const std::vector list, Positions pos) { } std::vector DetectorImpl::getCtbDacNames() const { + if (!isChipTestBoard()) + throw RuntimeError("Named DACs only for CTB"); return ctb_shm()->getDacNames(); } void DetectorImpl::setCtbDacNames(const std::vector &names) { + if (!isChipTestBoard()) + throw RuntimeError("Named DACs only for CTB"); ctb_shm()->setDacNames(names); } std::string DetectorImpl::getCtbDacName(defs::dacIndex i) const { + if (!isChipTestBoard()) + throw RuntimeError("Named DACs only for CTB"); return ctb_shm()->getDacName(static_cast(i)); } void DetectorImpl::setCtbDacName(const defs::dacIndex index, const std::string &name) { + if (!isChipTestBoard()) + throw RuntimeError("Named DACs only for CTB"); ctb_shm()->setDacName(index, name); } std::vector DetectorImpl::getCtbAdcNames() const { + if (!isChipTestBoard()) + throw RuntimeError("Named ADCs only for CTB"); return ctb_shm()->getAdcNames(); } void DetectorImpl::setCtbAdcNames(const std::vector &names) { + if (!isChipTestBoard()) + throw RuntimeError("Named ADCs only for CTB"); ctb_shm()->setAdcNames(names); } std::string DetectorImpl::getCtbAdcName(const int i) const { + if (!isChipTestBoard()) + throw RuntimeError("Named ADCs only for CTB"); return ctb_shm()->getAdcName(i); } void DetectorImpl::setCtbAdcName(const int index, const std::string &name) { + if (!isChipTestBoard()) + throw RuntimeError("Named ADCs only for CTB"); ctb_shm()->setAdcName(index, name); } std::vector DetectorImpl::getCtbSignalNames() const { + if (!isChipTestBoard()) + throw RuntimeError("Named signals only for CTB"); return ctb_shm()->getSignalNames(); } void DetectorImpl::setCtbSignalNames(const std::vector &names) { + if (!isChipTestBoard()) + throw RuntimeError("Named signals only for CTB"); ctb_shm()->setSignalNames(names); } std::string DetectorImpl::getCtbSignalName(const int i) const { + if (!isChipTestBoard()) + throw RuntimeError("Named signals only for CTB"); return ctb_shm()->getSignalName(i); } void DetectorImpl::setCtbSignalName(const int index, const std::string &name) { + if (!isChipTestBoard()) + throw RuntimeError("Named signals only for CTB"); ctb_shm()->setSignalName(index, name); } std::vector DetectorImpl::getCtbPowerNames() const { + if (!isChipTestBoard()) + throw RuntimeError("Named Powers only for CTB"); return ctb_shm()->getPowerNames(); } void DetectorImpl::setCtbPowerNames(const std::vector &names) { + if (!isChipTestBoard()) + throw RuntimeError("Named Powers only for CTB"); ctb_shm()->setPowerNames(names); } std::string DetectorImpl::getCtbPowerName(const defs::dacIndex i) const { + if (!isChipTestBoard()) + throw RuntimeError("Named Powers only for CTB"); return ctb_shm()->getPowerName(static_cast(i - defs::V_POWER_A)); } void DetectorImpl::setCtbPowerName(const defs::dacIndex index, const std::string &name) { + if (!isChipTestBoard()) + throw RuntimeError("Named Powers only for CTB"); ctb_shm()->setPowerName(static_cast(index - defs::V_POWER_A), name); } std::vector DetectorImpl::getCtbSlowADCNames() const { + if (!isChipTestBoard()) + throw RuntimeError("Named Slow ADCs only for CTB"); return ctb_shm()->getSlowADCNames(); } void DetectorImpl::setCtbSlowADCNames(const std::vector &names) { + if (!isChipTestBoard()) + throw RuntimeError("Named Slow ADCs only for CTB"); ctb_shm()->setSlowADCNames(names); } std::string DetectorImpl::getCtbSlowADCName(const defs::dacIndex i) const { + if (!isChipTestBoard()) + throw RuntimeError("Named Slow ADCs only for CTB"); return ctb_shm()->getSlowADCName(static_cast(i - defs::SLOW_ADC0)); } void DetectorImpl::setCtbSlowADCName(const defs::dacIndex index, const std::string &name) { + if (!isChipTestBoard()) + throw RuntimeError("Named Slow ADCs only for CTB"); ctb_shm()->setSlowADCName(static_cast(index - defs::SLOW_ADC0), name); } +int DetectorImpl::getRegisterDefinitionsCount() const { + if (!isChipTestBoard()) + throw RuntimeError("Register Definitions only for CTB"); + return ctb_shm()->getRegisterNamesCount(); +} + +void DetectorImpl::setRegisterDefinition(const std::string &name, + RegisterAddress addr) { + if (!isChipTestBoard()) + throw RuntimeError("Register Definitions only for CTB"); + ctb_shm()->setRegisterName(name, addr); +} + +bool DetectorImpl::hasRegisterDefinition(const std::string &name) const { + if (!isChipTestBoard()) + throw RuntimeError("Register Definitions only for CTB"); + return ctb_shm()->hasRegisterName(name); +} + +bool DetectorImpl::hasRegisterDefinition(RegisterAddress addr) const { + if (!isChipTestBoard()) + throw RuntimeError("Register Definitions only for CTB"); + return ctb_shm()->hasRegisterAddress(addr); +} + +RegisterAddress +DetectorImpl::getRegisterAddress(const std::string &name) const { + if (!isChipTestBoard()) + throw RuntimeError("Register Definitions only for CTB"); + return ctb_shm()->getRegisterAddress(name); +} + +std::string DetectorImpl::getRegisterName(RegisterAddress addr) const { + if (!isChipTestBoard()) + throw RuntimeError("Register Definitions only for CTB"); + return ctb_shm()->getRegisterName(addr); +} + +void DetectorImpl::clearRegisterDefinitions() { + if (!isChipTestBoard()) + throw RuntimeError("Register Definitions only for CTB"); + ctb_shm()->clearRegisterNames(); +} + +void DetectorImpl::setRegisterDefinitions( + const std::map &list) { + if (!isChipTestBoard()) + throw RuntimeError("Register Definitions only for CTB"); + ctb_shm()->setRegisterNames(list); +} + +std::map +DetectorImpl::getRegisterDefinitions() const { + if (!isChipTestBoard()) + throw RuntimeError("Register Definitions only for CTB"); + return ctb_shm()->getRegisterNames(); +} + +int DetectorImpl::getBitDefinitionsCount() const { + if (!isChipTestBoard()) + throw RuntimeError("Bit Definitions only for CTB"); + return ctb_shm()->getBitNamesCount(); +} + +void DetectorImpl::setBitDefinition(const std::string &name, BitAddress addr) { + if (!isChipTestBoard()) + throw RuntimeError("Bit Definitions only for CTB"); + ctb_shm()->setBitName(name, addr); +} + +bool DetectorImpl::hasBitDefinition(const std::string &name) const { + if (!isChipTestBoard()) + throw RuntimeError("Bit Definitions only for CTB"); + return ctb_shm()->hasBitName(name); +} + +bool DetectorImpl::hasBitDefinition(BitAddress addr) const { + if (!isChipTestBoard()) + throw RuntimeError("Bit Definitions only for CTB"); + return ctb_shm()->hasBitAddress(addr); +} + +std::string DetectorImpl::toRegisterNameBitString(BitAddress addr) const { + if (!isChipTestBoard()) + throw RuntimeError("Bit Definitions only for CTB"); + return ctb_shm()->toRegisterNameBitString(addr); +} + +BitAddress DetectorImpl::getBitAddress(const std::string &name) const { + if (!isChipTestBoard()) + throw RuntimeError("Bit Definitions only for CTB"); + return ctb_shm()->getBitAddress(name); +} + +std::string DetectorImpl::getBitName(BitAddress addr) const { + if (!isChipTestBoard()) + throw RuntimeError("Bit Definitions only for CTB"); + return ctb_shm()->getBitName(addr); +} + +void DetectorImpl::clearBitDefinitions() { + if (!isChipTestBoard()) + throw RuntimeError("Bit Definitions only for CTB"); + ctb_shm()->clearBitNames(); +} + +void DetectorImpl::setBitDefinitions( + const std::map &list) { + if (!isChipTestBoard()) + throw RuntimeError("Bit Definitions only for CTB"); + ctb_shm()->setBitNames(list); +} + +std::map DetectorImpl::getBitDefinitions() const { + if (!isChipTestBoard()) + throw RuntimeError("Bit Definitions only for CTB"); + return ctb_shm()->getBitNames(); +} + +Result DetectorImpl::readRegister(const std::string ®_name, + Positions pos) const { + if (!isChipTestBoard()) { + throw RuntimeError("Register Definitions only for CTB. Use hard coded " + "values instead."); + } + auto addr = getRegisterAddress(reg_name); + return readRegister(addr, pos); +} + +void DetectorImpl::writeRegister(const std::string ®_name, RegisterValue val, + bool validate, Positions pos) { + if (!isChipTestBoard()) { + throw RuntimeError("Register Definitions only for CTB. Use hard coded " + "values instead."); + } + auto addr = getRegisterAddress(reg_name); + writeRegister(addr, val, validate, pos); +} + +void DetectorImpl::setBit(const std::string &bit_name, bool validate, + Positions pos) { + if (!isChipTestBoard()) { + throw RuntimeError( + "Bit Definitions only for CTB. Use hard coded values instead."); + } + auto addr = getBitAddress(bit_name); + setBit(addr, validate, pos); +} + +void DetectorImpl::clearBit(const std::string &bit_name, bool validate, + Positions pos) { + if (!isChipTestBoard()) { + throw RuntimeError( + "Bit Definitions only for CTB. Use hard coded values instead."); + } + auto addr = getBitAddress(bit_name); + clearBit(addr, validate, pos); +} + +Result DetectorImpl::getBit(const std::string &bit_name, + Positions pos) const { + if (!isChipTestBoard()) { + throw RuntimeError( + "Bit Definitions only for CTB. Use hard coded values instead."); + } + auto addr = getBitAddress(bit_name); + return getBit(addr, pos); +} + +Result DetectorImpl::readRegister(RegisterAddress addr, + Positions pos) const { + return Parallel(&Module::readRegister, pos, addr); +} + +void DetectorImpl::writeRegister(RegisterAddress addr, RegisterValue val, + bool validate, Positions pos) { + Parallel(&Module::writeRegister, pos, addr, val, validate); +} + +void DetectorImpl::setBit(BitAddress addr, bool validate, Positions pos) { + Parallel(&Module::setBit, pos, addr, validate); +} + +void DetectorImpl::clearBit(BitAddress addr, bool validate, Positions pos) { + Parallel(&Module::clearBit, pos, addr, validate); +} + +Result DetectorImpl::getBit(BitAddress addr, Positions pos) const { + return Parallel(&Module::getBit, pos, addr); +} + } // namespace sls \ No newline at end of file diff --git a/slsDetectorSoftware/src/DetectorImpl.h b/slsDetectorSoftware/src/DetectorImpl.h index fddccfe2f..921623b32 100644 --- a/slsDetectorSoftware/src/DetectorImpl.h +++ b/slsDetectorSoftware/src/DetectorImpl.h @@ -183,6 +183,11 @@ class DetectorImpl : public virtual slsDetectorDefs { bool isAllPositions(Positions pos) const; + inline bool isChipTestBoard() const { + return (shm()->detType == defs::CHIPTESTBOARD || + shm()->detType == defs::XILINX_CHIPTESTBOARD); + } + /** set acquiring flag in shared memory */ void setAcquiringFlag(bool flag); @@ -328,6 +333,43 @@ class DetectorImpl : public virtual slsDetectorDefs { void setCtbSlowADCNames(const std::vector &names); void setCtbSlowADCName(const defs::dacIndex index, const std::string &name); + int getRegisterDefinitionsCount() const; + void setRegisterDefinition(const std::string &name, RegisterAddress addr); + bool hasRegisterDefinition(const std::string &name) const; + bool hasRegisterDefinition(RegisterAddress addr) const; + RegisterAddress getRegisterAddress(const std::string &name) const; + std::string getRegisterName(RegisterAddress addr) const; + void clearRegisterDefinitions(); + void + setRegisterDefinitions(const std::map &list); + std::map getRegisterDefinitions() const; + int getBitDefinitionsCount() const; + void setBitDefinition(const std::string &name, BitAddress addr); + bool hasBitDefinition(const std::string &name) const; + bool hasBitDefinition(BitAddress addr) const; + std::string toRegisterNameBitString(BitAddress addr) const; + BitAddress getBitAddress(const std::string &name) const; + std::string getBitName(BitAddress addr) const; + void clearBitDefinitions(); + void setBitDefinitions(const std::map &list); + std::map getBitDefinitions() const; + + Result readRegister(const std::string ®_name, + Positions pos) const; + void writeRegister(const std::string ®_name, RegisterValue val, + bool validate, Positions pos); + void setBit(const std::string &bit_name, bool validate, Positions pos); + void clearBit(const std::string &bit_name, bool validate, Positions pos); + Result getBit(const std::string &bit_name, Positions pos) const; + + Result readRegister(RegisterAddress addr, + Positions pos = {}) const; + void writeRegister(RegisterAddress addr, RegisterValue val, + bool validate = false, Positions pos = {}); + void setBit(BitAddress addr, bool validate = false, Positions pos = {}); + void clearBit(BitAddress addr, bool validate = false, Positions pos = {}); + Result getBit(BitAddress addr, Positions pos = {}) const; + private: /** * Creates/open shared memory, initializes detector structure and members diff --git a/slsDetectorSoftware/src/MapOnStack.h b/slsDetectorSoftware/src/MapOnStack.h new file mode 100644 index 000000000..70a7aada1 --- /dev/null +++ b/slsDetectorSoftware/src/MapOnStack.h @@ -0,0 +1,218 @@ +#pragma once + +// #include "sls/StaticVector.h" +#include "sls/string_utils.h" + +#include +#include +#include +#include +#include + +namespace sls { + +template struct FixedString { + char data_[N]{}; + constexpr FixedString() noexcept { memset(data_, 0, N); } + FixedString(const char (&s)[N]) { + if (N <= 1) { + throw std::runtime_error("FixedString cannot be empty"); + } + strcpy_checked(data_, s); + } + FixedString(const std::string &s) { + if (s.size() <= 1) { + throw std::runtime_error("FixedString cannot be empty"); + } + strcpy_checked(data_, s); + } + bool operator==(const FixedString &other) const noexcept { + return std::strncmp(data_, other.data_, N) == 0; + } + bool operator<(const FixedString &other) const noexcept { + return std::strncmp(data_, other.data_, N) < 0; + } + std::string str() const { return std::string(data_); } +}; + +template + +class MapOnStack { + // for shared memory use only trivially copyable types + static_assert(std::is_trivially_copyable_v); + static_assert(std::is_trivially_copyable_v); + static_assert(std::is_standard_layout_v); + static_assert(std::is_standard_layout_v); + static_assert(!std::is_pointer_v); + static_assert(!std::is_pointer_v); + + public: + constexpr MapOnStack() noexcept = default; + + constexpr size_t size() const noexcept { return current_size_; } + constexpr size_t capacity() const noexcept { return Capacity; } + constexpr bool empty() const noexcept { return current_size_ == 0; } + void clear() noexcept { current_size_ = 0; } + + bool containsKey(const Key &key) const { + return lookupEntryByKey(key).has_value(); + } + + bool hasValue(const Value &value) const { + return lookupEntryByValue(value).has_value(); + } + + void addKeyOrSetValue(const Key &key, const Value &value) { + if (auto entry = findEntryByKey(key)) { + (*entry)->setValue(value); + return; + } + addEntry(key, value); + } + + void addKey(const Key &key, const Value &value) { addEntry(key, value); } + + void setValue(const Key &key, const Value &value) { + if (auto entry = findEntryByKey(key)) { + (*entry)->setValue(value); + return; + } + throw std::runtime_error("Key not found. Cannot set value."); + } + + Value getValue(const Key &key) const { + auto val = lookupEntryByKey(key); + if (!val.has_value()) { + throw std::runtime_error("No entry found for key"); + } + return val.value(); + } + + Key getKey(const Value &value) const { + auto key = lookupEntryByValue(value); + if (!key.has_value()) { + throw std::runtime_error("No entry found for value"); + } + return key.value(); + } + + void setMap(const std::map &list) { + if (list.size() >= Capacity) { + throw std::runtime_error("List size exceeds maximum Capacity"); + } + clear(); + for (const auto &[key, value] : list) { + addEntry(key, value); + } + } + + std::map getMap() const { + std::map list; + for (size_t i = 0; i != current_size_; ++i) + list[data_[i].key()] = data_[i].value(); + return list; + } + + private: + struct Entry { + Key key_{}; + Value value_{}; + constexpr Entry() noexcept = default; + constexpr Entry(const Key &key, const Value &value) + : key_(key), value_(value) {} + constexpr Key key() const noexcept { return key_; } + constexpr Value value() const noexcept { return value_; } + constexpr void setValue(Value value) noexcept { value_ = value; } + }; + + Entry data_[Capacity]; + size_t current_size_{0}; + // StaticVector entries_; + + std::optional findEntryByKey(const Key &key) { + auto it = std::find_if(data_, data_ + current_size_, + [&key](Entry &e) { return (e.key() == key); }); + if (it != data_ + current_size_) + return it; + return std::nullopt; + } + + std::optional findEntryByKey(const Key &key) const { + auto it = + std::find_if(data_, data_ + current_size_, + [&key](const Entry &e) { return (e.key() == key); }); + if (it != data_ + current_size_) + return it; + return std::nullopt; + } + + std::optional findEntryByValue(Value value) { + if (!Unique_Values) { + throw std::runtime_error( + "Cannot lookup by value when unique values are not enforced."); + } + auto it = + std::find_if(data_, data_ + current_size_, + [&value](Entry &e) { return e.value() == value; }); + if (it != data_ + current_size_) + return it; + return std::nullopt; + } + + std::optional findEntryByValue(Value value) const { + if (!Unique_Values) { + throw std::runtime_error( + "Cannot lookup by value when unique values are not enforced."); + } + auto it = std::find_if( + data_, data_ + current_size_, + [&value](const Entry &e) { return e.value() == value; }); + if (it != data_ + current_size_) + return it; + return std::nullopt; + } + + std::optional lookupEntryByKey(const Key &key) const { + auto entry = findEntryByKey(key); + return (entry ? std::optional((*entry)->value()) : std::nullopt); + } + + std::optional lookupEntryByValue(Value value) const { + auto entry = findEntryByValue(value); + return (entry ? std::optional((*entry)->key()) : std::nullopt); + } + + void checkDuplicateKey(const Key &key) const { + if (auto entry = findEntryByKey(key)) { + throw std::runtime_error( + "Key already exists. Cannot have duplicate keys."); + } + } + + void checkDuplicateValue(Value value) const { + if (Unique_Values) { + if (auto entry = findEntryByValue(value)) { + throw std::runtime_error( + "Value already assigned to another key '" + + (*entry)->key().str() + "'. Cannot assign it again."); + } + } + } + + void checkSize() const { + if (current_size_ >= Capacity) { + throw std::runtime_error("Maximum capacity reached"); + } + } + + void addEntry(const Key &key, const Value &value) { + checkSize(); + checkDuplicateKey(key); + checkDuplicateValue(value); + + data_[current_size_] = Entry(key, value); + ++(current_size_); + } +}; + +} // namespace sls diff --git a/slsDetectorSoftware/src/Module.cpp b/slsDetectorSoftware/src/Module.cpp index 8cde3f072..6167f585d 100644 --- a/slsDetectorSoftware/src/Module.cpp +++ b/slsDetectorSoftware/src/Module.cpp @@ -2575,8 +2575,9 @@ void Module::setReceiverDbitList(std::vector list) { } } auto r = stableRemoveDuplicates(list); - if(r) + if (r) { LOG(logWARNING) << "Removed duplicated from receiver dbit list"; + } StaticVector arg = list; sendToReceiver(F_SET_RECEIVER_DBIT_LIST, arg, nullptr); @@ -2914,29 +2915,30 @@ void Module::setUpdateMode(const bool updatemode) { << "): Update Mode set to " << updatemode << "!"; } -uint32_t Module::readRegister(uint32_t addr) const { - return sendToDetectorStop(F_READ_REGISTER, addr); +RegisterValue Module::readRegister(RegisterAddress addr) const { + return sendToDetectorStop(F_READ_REGISTER, addr.value()); } -void Module::writeRegister(uint32_t addr, uint32_t val, bool validate) { - uint32_t args[]{addr, val, static_cast(validate)}; +void Module::writeRegister(RegisterAddress addr, RegisterValue val, + bool validate) { + uint32_t args[]{addr.value(), val.value(), static_cast(validate)}; return sendToDetectorStop(F_WRITE_REGISTER, args, nullptr); } -void Module::setBit(uint32_t addr, int n, bool validate) { - uint32_t args[] = {addr, static_cast(n), +void Module::setBit(BitAddress bitAddr, bool validate) { + uint32_t args[] = {bitAddr.address().value(), bitAddr.bitPosition(), static_cast(validate)}; sendToDetectorStop(F_SET_BIT, args, nullptr); } -void Module::clearBit(uint32_t addr, int n, bool validate) { - uint32_t args[] = {addr, static_cast(n), +void Module::clearBit(BitAddress bitAddr, bool validate) { + uint32_t args[] = {bitAddr.address().value(), bitAddr.bitPosition(), static_cast(validate)}; sendToDetectorStop(F_CLEAR_BIT, args, nullptr); } -int Module::getBit(uint32_t addr, int n) { - uint32_t args[2] = {addr, static_cast(n)}; +int Module::getBit(BitAddress bitAddr) const { + uint32_t args[2] = {bitAddr.address().value(), bitAddr.bitPosition()}; return sendToDetectorStop(F_GET_BIT, args); } diff --git a/slsDetectorSoftware/src/Module.h b/slsDetectorSoftware/src/Module.h index d1fd4a325..d23cc095e 100644 --- a/slsDetectorSoftware/src/Module.h +++ b/slsDetectorSoftware/src/Module.h @@ -5,6 +5,7 @@ #include "sls/ClientSocket.h" #include "sls/Pattern.h" #include "sls/StaticVector.h" +#include "sls/bit_utils.h" #include "sls/logger.h" #include "sls/network_utils.h" #include "sls/sls_detector_defs.h" @@ -579,11 +580,11 @@ class Module : public virtual slsDetectorDefs { void rebootController(); bool getUpdateMode() const; void setUpdateMode(const bool updatemode); - uint32_t readRegister(uint32_t addr) const; - void writeRegister(uint32_t addr, uint32_t val, bool validate); - void setBit(uint32_t addr, int n, bool validate); - void clearBit(uint32_t addr, int n, bool validate); - int getBit(uint32_t addr, int n); + RegisterValue readRegister(RegisterAddress addr) const; + void writeRegister(RegisterAddress addr, RegisterValue val, bool validate); + void setBit(BitAddress bitAddr, bool validate); + void clearBit(BitAddress bitAddr, bool validate); + int getBit(BitAddress bitAddr) const; void executeFirmwareTest(); void executeBusTest(); void writeAdcRegister(uint32_t addr, uint32_t val); diff --git a/slsDetectorSoftware/src/SharedMemory.h b/slsDetectorSoftware/src/SharedMemory.h index 2265d2f96..bbdcfdd66 100644 --- a/slsDetectorSoftware/src/SharedMemory.h +++ b/slsDetectorSoftware/src/SharedMemory.h @@ -28,25 +28,26 @@ // ********************** Defines for shared memory. ********************** // WARNING! before chaning these search the codebase for their usage! +// date when IsValid boolean introduced into every shm structure +// (to look out for shm that still exists due to other mapped resources) #define SHM_IS_VALID_CHECK_VERSION 0x250820 -//Max shared memory name length in macOS is 31 characters +// Max shared memory name length in macOS is 31 characters #ifdef __APPLE__ -#define SHM_DETECTOR_PREFIX "/sls_" -#define SHM_MODULE_PREFIX "_mod_" +#define SHM_DETECTOR_PREFIX "/sls_" +#define SHM_MODULE_PREFIX "_mod_" #else -#define SHM_DETECTOR_PREFIX "/slsDetectorPackage_detector_" -#define SHM_MODULE_PREFIX "_module_" +#define SHM_DETECTOR_PREFIX "/slsDetectorPackage_detector_" +#define SHM_MODULE_PREFIX "_module_" #endif -#define SHM_ENV_NAME "SLSDETNAME" +#define SHM_ENV_NAME "SLSDETNAME" // ************************************************************************ namespace sls { class CtbConfig; - template constexpr bool is_type() { return std::is_same_v, T>; } @@ -94,17 +95,16 @@ template class SharedMemory { unmapSharedMemory(); } + /** memory is valid if it has the IsValid flag and is true */ bool memoryHasValidFlag() const { if (shared_struct == nullptr) { throw SharedMemoryError( "Shared memory not mapped. Cannot check validity."); } - // CtbConfig did not have shmversion before, so exact value check - if constexpr (is_type()) { - if (shared_struct->shmversion == SHM_IS_VALID_CHECK_VERSION) { - return true; - } - } else if (shared_struct->shmversion >= SHM_IS_VALID_CHECK_VERSION) { + // CtbConfig also works (shmversion didnt exist prior, but it would read + // "20" = length size) so shmversion should always be >= isValid + // introduced date (0x250820) + if (shared_struct->shmversion >= SHM_IS_VALID_CHECK_VERSION) { return true; } return false; @@ -279,11 +279,12 @@ template class SharedMemory { throw SharedMemoryError(msg); } - #ifdef __APPLE__ - // On macOS, fstat returns the allocated size and not the requested size. - // This means we can't check for size since we always get for example 16384 bytes. +#ifdef __APPLE__ + // On macOS, fstat returns the allocated size and not the requested + // size. This means we can't check for size since we always get for + // example 16384 bytes. return; - #endif +#endif auto actual_size = static_cast(sb.st_size); auto expected_size = sizeof(T); if (actual_size != expected_size) { diff --git a/slsDetectorSoftware/src/inferAction.cpp b/slsDetectorSoftware/src/inferAction.cpp index 0b72bcd06..8b0c44744 100644 --- a/slsDetectorSoftware/src/inferAction.cpp +++ b/slsDetectorSoftware/src/inferAction.cpp @@ -400,6 +400,10 @@ int InferAction::chipversion() { int InferAction::clearbit() { + if (args.size() == 1) { + return slsDetectorDefs::PUT_ACTION; + } + if (args.size() == 2) { return slsDetectorDefs::PUT_ACTION; } @@ -788,6 +792,66 @@ int InferAction::defaultpattern() { } } +int InferAction::define_bit() { + + if (args.size() == 1) { + return slsDetectorDefs::GET_ACTION; + } + + if (args.size() == 2) { + return slsDetectorDefs::GET_ACTION; + } + + if (args.size() == 3) { + return slsDetectorDefs::PUT_ACTION; + } + + else { + + throw RuntimeError("Could not infer action: Wrong number of arguments"); + } +} + +int InferAction::define_reg() { + + if (args.size() == 1) { + return slsDetectorDefs::GET_ACTION; + } + + if (args.size() == 2) { + return slsDetectorDefs::PUT_ACTION; + } + + else { + + throw RuntimeError("Could not infer action: Wrong number of arguments"); + } +} + +int InferAction::definelist_bit() { + + if (args.size() == 0) { + return slsDetectorDefs::GET_ACTION; + } + + else { + + throw RuntimeError("Could not infer action: Wrong number of arguments"); + } +} + +int InferAction::definelist_reg() { + + if (args.size() == 0) { + return slsDetectorDefs::GET_ACTION; + } + + else { + + throw RuntimeError("Could not infer action: Wrong number of arguments"); + } +} + int InferAction::delay() { if (args.size() == 0) { @@ -1498,6 +1562,10 @@ int InferAction::gates() { int InferAction::getbit() { + if (args.size() == 1) { + return slsDetectorDefs::GET_ACTION; + } + if (args.size() == 2) { return slsDetectorDefs::GET_ACTION; } @@ -3055,6 +3123,10 @@ int InferAction::serialnumber() { int InferAction::setbit() { + if (args.size() == 1) { + return slsDetectorDefs::PUT_ACTION; + } + if (args.size() == 2) { return slsDetectorDefs::PUT_ACTION; } diff --git a/slsDetectorSoftware/src/inferAction.h b/slsDetectorSoftware/src/inferAction.h index ffc6944d7..5e4c281ad 100644 --- a/slsDetectorSoftware/src/inferAction.h +++ b/slsDetectorSoftware/src/inferAction.h @@ -62,6 +62,10 @@ class InferAction { int dbitpipeline(); int defaultdac(); int defaultpattern(); + int define_bit(); + int define_reg(); + int definelist_bit(); + int definelist_reg(); int delay(); int delayl(); int detectorserverversion(); @@ -394,6 +398,10 @@ class InferAction { {"dbitpipeline", &InferAction::dbitpipeline}, {"defaultdac", &InferAction::defaultdac}, {"defaultpattern", &InferAction::defaultpattern}, + {"define_bit", &InferAction::define_bit}, + {"define_reg", &InferAction::define_reg}, + {"definelist_bit", &InferAction::definelist_bit}, + {"definelist_reg", &InferAction::definelist_reg}, {"delay", &InferAction::delay}, {"delayl", &InferAction::delayl}, {"detectorserverversion", &InferAction::detectorserverversion}, diff --git a/slsDetectorSoftware/tests/Caller/test-Caller-chiptestboard.cpp b/slsDetectorSoftware/tests/Caller/test-Caller-chiptestboard.cpp index 2bc827476..54231950c 100644 --- a/slsDetectorSoftware/tests/Caller/test-Caller-chiptestboard.cpp +++ b/slsDetectorSoftware/tests/Caller/test-Caller-chiptestboard.cpp @@ -1030,37 +1030,41 @@ TEST_CASE("v_abcd", "[.cmdcall]") { Caller caller(&det); auto det_type = det.getDetectorType().squash(); - std::vector cmds{"v_a", "v_b", "v_c", "v_d"}; - std::vector indices{defs::V_POWER_A, defs::V_POWER_B, - defs::V_POWER_C, defs::V_POWER_D}; - if (det.isVirtualDetectorServer().tsquash("Inconsistent virtual servers")) { - cmds.push_back("v_io"); - indices.push_back(defs::V_POWER_IO); - } - for (size_t i = 0; i < cmds.size(); ++i) { - if (det_type == defs::CHIPTESTBOARD || - det_type == defs::XILINX_CHIPTESTBOARD) { - auto prev_val = det.getPower(indices[i]); - { - std::ostringstream oss; - caller.call(cmds[i], {"0"}, -1, PUT, oss); - REQUIRE(oss.str() == cmds[i] + " 0\n"); - } - { - std::ostringstream oss1, oss2; - caller.call(cmds[i], {"1200"}, -1, PUT, oss1); - REQUIRE(oss1.str() == cmds[i] + " 1200\n"); - caller.call(cmds[i], {}, -1, GET, oss2); - REQUIRE(oss2.str() == cmds[i] + " 1200\n"); - } - for (int i = 0; i != det.size(); ++i) { - det.setPower(indices[i], prev_val[i], {i}); - } + std::vector cmds{"v_a", "v_b", "v_c", "v_d", "v_io"}; + std::vector indices{defs::V_POWER_A, defs::V_POWER_B, + defs::V_POWER_C, defs::V_POWER_D, + defs::V_POWER_IO}; - } else { - REQUIRE_THROWS(caller.call(cmds[i], {}, -1, GET)); + for (size_t i = 0; i < cmds.size(); ++i) { + if (det_type == defs::CHIPTESTBOARD || + det_type == defs::XILINX_CHIPTESTBOARD) { + auto prev_val = det.getPower(indices[i]); + { + std::ostringstream oss; + caller.call(cmds[i], {"0"}, -1, PUT, oss); + REQUIRE(oss.str() == cmds[i] + " 0\n"); + } + { + std::ostringstream oss1, oss2; + caller.call(cmds[i], {"1200"}, -1, PUT, oss1); + REQUIRE(oss1.str() == cmds[i] + " 1200\n"); + caller.call(cmds[i], {}, -1, GET, oss2); + REQUIRE(oss2.str() == cmds[i] + " 1200\n"); + } + for (int i = 0; i != det.size(); ++i) { + if (det_type == defs::XILINX_CHIPTESTBOARD && + prev_val[i] == -100) { + prev_val[i] = 0; + continue; + } + det.setPower(indices[i], prev_val[i], {i}); + } + + } else { + REQUIRE_THROWS(caller.call(cmds[i], {}, -1, GET)); + } } } } @@ -1330,4 +1334,366 @@ TEST_CASE("led", "[.cmdcall]") { } } +TEST_CASE("define_reg", "[.cmdcall][.definecmds]") { + Detector det; + Caller caller(&det); + auto det_type = det.getDetectorType().squash(); + + if (det_type == defs::CHIPTESTBOARD || + det_type == defs::XILINX_CHIPTESTBOARD) { + + auto prev_reg_defines = det.getRegisterDefinitions(); + auto prev_bit_defines = det.getBitDefinitions(); + det.clearRegisterDefinitions(); + det.clearBitDefinitions(); + + { + // invalid puts + // missing arg + REQUIRE_THROWS(caller.call("define_reg", {}, -1, GET)); + // missing arg + REQUIRE_THROWS(caller.call("define_reg", {"TEST_REG"}, -1, PUT)); + // invalid module id + REQUIRE_THROWS( + caller.call("define_reg", {"TEST_REG", "0x201"}, 0, PUT)); + + // valid put + REQUIRE_NOTHROW( + caller.call("define_reg", {"TEST_REG", "0x200"}, -1, PUT)); + // modify reg + REQUIRE_NOTHROW( + caller.call("define_reg", {"TEST_REG", "0x201"}, -1, PUT)); + REQUIRE_NOTHROW( + caller.call("define_reg", {"TEST_REG2", "0x202"}, -1, PUT)); + + // invalid puts + // existing reg addr + REQUIRE_THROWS( + caller.call("define_reg", {"TEST_REG3", "0x201"}, -1, PUT)); + + // valid gets + { + // get by name + std::ostringstream oss; + REQUIRE_NOTHROW( + caller.call("define_reg", {"TEST_REG"}, -1, GET, oss)); + REQUIRE(oss.str() == "define_reg 0x201\n"); + } + { + // get by addr + std::ostringstream oss; + REQUIRE_NOTHROW( + caller.call("define_reg", {"0x201"}, -1, GET, oss)); + REQUIRE(oss.str() == "define_reg TEST_REG\n"); + } + + // invalid gets + // doesnt exist + REQUIRE_THROWS(caller.call("define_reg", {"TEST_REG3"}, -1, GET)); + REQUIRE_THROWS(caller.call("define_reg", {"0x203"}, -1, GET)); + // ensure correct exception message + try { + caller.call("define_reg", {"0x203"}, -1, GET); + } catch (const std::exception &e) { + REQUIRE(std::string(e.what()).find( + "No entry found for value") != std::string::npos); + } + } + det.clearRegisterDefinitions(); + det.clearBitDefinitions(); + + det.setRegisterDefinitions(prev_reg_defines); + det.setBitDefinitions(prev_bit_defines); + + } else { + REQUIRE_THROWS( + caller.call("define_reg", {"TEST_REG", "0x200"}, -1, PUT)); + REQUIRE_THROWS(caller.call("define_reg", {"TEST_REG"}, -1, GET)); + } +} + +TEST_CASE("define_bit", "[.cmdcall][.definecmds]") { + Detector det; + Caller caller(&det); + auto det_type = det.getDetectorType().squash(); + + if (det_type == defs::CHIPTESTBOARD || + det_type == defs::XILINX_CHIPTESTBOARD) { + + auto prev_reg_defines = det.getRegisterDefinitions(); + auto prev_bit_defines = det.getBitDefinitions(); + + det.clearRegisterDefinitions(); + det.clearBitDefinitions(); + det.setRegisterDefinition("TEST_REG", RegisterAddress(0x201)); + det.setRegisterDefinition("TEST_REG2", RegisterAddress(0x202)); + + { + // invalid puts + // skipped register + REQUIRE_THROWS( + caller.call("define_bit", {"TEST_BIT", "1"}, -1, PUT)); + // named register doesnt exist + REQUIRE_THROWS(caller.call( + "define_bit", {"TEST_BIT", "RANDOM_REG", "1"}, -1, PUT)); + // invalid bit position + REQUIRE_THROWS( + caller.call("define", {"TEST_BIT", "TEST_REG", "32"}, -1, PUT)); + + // valid puts + REQUIRE_NOTHROW(caller.call( + "define_bit", {"TEST_BIT", "TEST_REG2", "1"}, -1, PUT)); + // modify reg + REQUIRE_NOTHROW(caller.call( + "define_bit", {"TEST_BIT", "TEST_REG", "1"}, -1, PUT)); + + // modify position + REQUIRE_NOTHROW(caller.call( + "define_bit", {"TEST_BIT", "TEST_REG", "2"}, -1, PUT)); + // another bit to same reg + REQUIRE_NOTHROW(caller.call( + "define_bit", {"TEST_BIT2", "TEST_REG", "4"}, -1, PUT)); + // bit to a different reg + REQUIRE_NOTHROW(caller.call( + "define_bit", {"TEST_BIT3", "TEST_REG2", "3"}, -1, PUT)); + + // valid gets + { + // get by name + std::ostringstream oss; + REQUIRE_NOTHROW( + caller.call("define_bit", {"TEST_BIT"}, -1, GET, oss)); + REQUIRE(oss.str() == "define_bit [TEST_REG, 2]\n"); + } + { + // get by addr+pos name + std::ostringstream oss; + REQUIRE_NOTHROW( + caller.call("define_bit", {"TEST_REG", "2"}, -1, GET, oss)); + REQUIRE(oss.str() == "define_bit TEST_BIT\n"); + } + { + // get by addr val + pos + std::ostringstream oss; + REQUIRE_NOTHROW( + caller.call("define_bit", {"0x201", "2"}, -1, GET, oss)); + REQUIRE(oss.str() == "define_bit TEST_BIT\n"); + } + + // invalid gets + // bit doesnt exist + REQUIRE_THROWS( + caller.call("define_bit", {"TEST_REG", "3"}, -1, GET)); + // addr doesnt exist + REQUIRE_THROWS( + caller.call("define_bit", {"TEST_REG3", "2"}, -1, GET)); + // ensure correct exception message + try { + caller.call("define_bit", {"TEST_REG", "3"}, -1, GET); + } catch (const std::exception &e) { + REQUIRE(std::string(e.what()).find( + "No entry found for value") != std::string::npos); + } + } + det.clearRegisterDefinitions(); + det.clearBitDefinitions(); + + det.setRegisterDefinitions(prev_reg_defines); + det.setBitDefinitions(prev_bit_defines); + + } else { + REQUIRE_THROWS( + caller.call("define_bit", {"TEST_BIT", "0x200", "2"}, -1, PUT)); + REQUIRE_THROWS(caller.call("define_bit", {"0x200", "2"}, -1, GET)); + } +} + +TEST_CASE("using define for reg, setbit, getbit and clearbit", + "[.cmdcall][.definecmds]") { + Detector det; + Caller caller(&det); + auto det_type = det.getDetectorType().squash(); + + if (det_type == defs::CHIPTESTBOARD || + det_type == defs::XILINX_CHIPTESTBOARD) { + + if (det.isVirtualDetectorServer().tsquash( + "inconsistent virtual values")) { + + auto prev_reg_defines = det.getRegisterDefinitions(); + auto prev_bit_defines = det.getBitDefinitions(); + + det.clearRegisterDefinitions(); + det.clearBitDefinitions(); + det.setRegisterDefinition("TEST_REG", RegisterAddress(0x201)); + det.setRegisterDefinition("TEST_REG2", RegisterAddress(0x202)); + det.setBitDefinition("TEST_BIT", + BitAddress(RegisterAddress(0x201), 2)); + det.setBitDefinition("TEST_BIT2", + BitAddress(RegisterAddress(0x201), 4)); + det.setBitDefinition("TEST_BIT3", + BitAddress(RegisterAddress(0x202), 3)); + + auto prev_val_addr = det.readRegister(RegisterAddress(0x201)); + auto prev_val_addr2 = det.readRegister(RegisterAddress(0x202)); + + // invalid puts + // doesnt exist addr + REQUIRE_THROWS( + caller.call("reg", {"RANDOM_REG", "0xf00"}, -1, PUT)); + REQUIRE_THROWS( + caller.call("clearbit", {"RANDOM_REG", "TEST_BIT"}, -1, PUT)); + REQUIRE_THROWS( + caller.call("setbit", {"RANDOM_REG", "TEST_BIT"}, -1, PUT)); + REQUIRE_THROWS( + caller.call("getbit", {"RANDOM_REG", "TEST_BIT"}, -1, GET)); + // using bit name for reg (only hardcoded values allowed) + REQUIRE_THROWS( + caller.call("reg", {"TEST_REG", "TEST_BIT"}, -1, PUT)); + // using bit name and reg (only bit names or both reg and bit + // hardcoded allowed) + REQUIRE_THROWS( + caller.call("clearbit", {"TEST_REG", "TEST_BIT"}, -1, PUT)); + REQUIRE_THROWS( + caller.call("setbit", {"TEST_REG", "TEST_BIT"}, -1, PUT)); + REQUIRE_THROWS( + caller.call("getbit", {"TEST_REG", "TEST_BIT"}, -1, GET)); + + // valid puts and gets + { + // reg hard coded value of 0 + std::ostringstream oss; + REQUIRE_NOTHROW( + caller.call("reg", {"TEST_REG", "0x0"}, -1, PUT)); + REQUIRE_NOTHROW(caller.call("reg", {"TEST_REG"}, -1, GET, oss)); + REQUIRE(oss.str() == "reg 0x0\n"); + } + { + // reg hard coded value + std::ostringstream oss; + REQUIRE_NOTHROW( + caller.call("reg", {"TEST_REG", "0x10"}, -1, PUT)); + REQUIRE_NOTHROW(caller.call("reg", {"TEST_REG"}, -1, GET, oss)); + REQUIRE(oss.str() == "reg 0x10\n"); + } + { + // set bit + std::ostringstream oss; + REQUIRE_NOTHROW(caller.call("setbit", {"TEST_BIT"}, -1, PUT)); + REQUIRE_NOTHROW( + caller.call("setbit", {"TEST_REG", "2"}, -1, PUT)); + REQUIRE_NOTHROW(caller.call("reg", {"TEST_REG"}, -1, GET, oss)); + REQUIRE(oss.str() == "reg 0x14\n"); + } + { + // get bit + std::ostringstream oss, oss2; + REQUIRE_NOTHROW( + caller.call("getbit", {"TEST_REG", "2"}, -1, GET, oss)); + REQUIRE(oss.str() == "getbit 1\n"); + REQUIRE_NOTHROW( + caller.call("getbit", {"TEST_BIT"}, -1, GET, oss2)); + REQUIRE(oss2.str() == "getbit 1\n"); + } + { + // clear bit + std::ostringstream oss; + REQUIRE_NOTHROW(caller.call("clearbit", {"TEST_BIT"}, -1, PUT)); + REQUIRE_NOTHROW( + caller.call("clearbit", {"TEST_REG", "2"}, -1, PUT)); + REQUIRE_NOTHROW(caller.call("reg", {"TEST_REG"}, -1, GET, oss)); + REQUIRE(oss.str() == "reg 0x10\n"); + } + for (int i = 0; i != det.size(); ++i) { + det.writeRegister(RegisterAddress(0x201), + RegisterValue(prev_val_addr[i]), false, {i}); + det.writeRegister(RegisterAddress(0x202), + RegisterValue(prev_val_addr2[i]), false, {i}); + } + det.clearRegisterDefinitions(); + det.clearBitDefinitions(); + + det.setRegisterDefinitions(prev_reg_defines); + det.setBitDefinitions(prev_bit_defines); + } + + } else { + REQUIRE_THROWS(caller.call("reg", {"TEST_REG", "0x200"}, -1, PUT)); + REQUIRE_THROWS(caller.call("reg", {"TEST_REG"}, -1, GET)); + } +} + +TEST_CASE("definelist_reg", "[.cmdcall][.definecmds]") { + Detector det; + Caller caller(&det); + auto det_type = det.getDetectorType().squash(); + + if (det_type == defs::CHIPTESTBOARD || + det_type == defs::XILINX_CHIPTESTBOARD) { + + auto prev_reg_defines = det.getRegisterDefinitions(); + + det.clearRegisterDefinitions(); + det.clearBitDefinitions(); + det.setRegisterDefinition("TEST_REG", RegisterAddress(0x201)); + det.setRegisterDefinition("TEST_REG2", RegisterAddress(0x202)); + + // invalid + // cannot put + REQUIRE_THROWS( + caller.call("definelist_reg", {"TEST_REG", "0x201"}, -1, PUT)); + // too many args + REQUIRE_THROWS(caller.call("definelist_reg", {"TEST_MACRO"}, -1, GET)); + + // valid + REQUIRE_NOTHROW(caller.call("definelist_reg", {}, -1, GET)); + det.clearRegisterDefinitions(); + det.clearBitDefinitions(); + + det.setRegisterDefinitions(prev_reg_defines); + } else { + REQUIRE_THROWS(caller.call("definelist_reg", {}, -1, GET)); + } +} + +TEST_CASE("definelist_bit", "[.cmdcall][.definecmds]") { + Detector det; + Caller caller(&det); + auto det_type = det.getDetectorType().squash(); + + if (det_type == defs::CHIPTESTBOARD || + det_type == defs::XILINX_CHIPTESTBOARD) { + + auto prev_reg_defines = det.getRegisterDefinitions(); + auto prev_bit_defines = det.getBitDefinitions(); + + det.clearRegisterDefinitions(); + det.clearBitDefinitions(); + det.setRegisterDefinition("TEST_REG", RegisterAddress(0x201)); + det.setRegisterDefinition("TEST_REG2", RegisterAddress(0x202)); + det.setBitDefinition("TEST_BIT", BitAddress(RegisterAddress(0x201), 2)); + det.setBitDefinition("TEST_BIT2", + BitAddress(RegisterAddress(0x201), 4)); + det.setBitDefinition("TEST_BIT3", + BitAddress(RegisterAddress(0x202), 3)); + + // invalid + // cannot put + REQUIRE_THROWS( + caller.call("definelist_bit", {"TEST_BIT", "0x201", "2"}, -1, PUT)); + // too many args + REQUIRE_THROWS(caller.call("definelist_bit", {"TEST_BIT"}, -1, GET)); + + // valid + REQUIRE_NOTHROW(caller.call("definelist_bit", {}, -1, GET)); + det.clearRegisterDefinitions(); + det.clearBitDefinitions(); + + det.setRegisterDefinitions(prev_reg_defines); + det.setBitDefinitions(prev_bit_defines); + } else { + REQUIRE_THROWS(caller.call("definelist_bit", {}, -1, GET)); + } +} + } // namespace sls diff --git a/slsDetectorSoftware/tests/Caller/test-Caller.cpp b/slsDetectorSoftware/tests/Caller/test-Caller.cpp index c96f6d4b1..22a70b54b 100644 --- a/slsDetectorSoftware/tests/Caller/test-Caller.cpp +++ b/slsDetectorSoftware/tests/Caller/test-Caller.cpp @@ -3267,7 +3267,7 @@ TEST_CASE("update", "[.cmdcall]") { } } -TEST_CASE("reg", "[.cmdcall]") { +TEST_CASE("reg", "[.cmdcall][.definecmds]") { Detector det; Caller caller(&det); auto det_type = det.getDetectorType().squash(); @@ -3284,14 +3284,14 @@ TEST_CASE("reg", "[.cmdcall]") { { std::ostringstream oss1, oss2; caller.call("reg", {saddr, "0x6", "--validate"}, -1, PUT, oss1); - REQUIRE(oss1.str() == "reg [" + saddr + ", 0x6]\n"); + REQUIRE(oss1.str() == "reg " + saddr + " 0x6\n"); caller.call("reg", {saddr}, -1, GET, oss2); REQUIRE(oss2.str() == "reg 0x6\n"); } { std::ostringstream oss1, oss2; caller.call("reg", {saddr, "0x5"}, -1, PUT, oss1); - REQUIRE(oss1.str() == "reg [" + saddr + ", 0x5]\n"); + REQUIRE(oss1.str() == "reg " + saddr + " 0x5\n"); caller.call("reg", {saddr}, -1, GET, oss2); REQUIRE(oss2.str() == "reg 0x5\n"); } @@ -3326,7 +3326,7 @@ TEST_CASE("adcreg", "[.cmdcall]") { } } -TEST_CASE("setbit", "[.cmdcall]") { +TEST_CASE("setbit", "[.cmdcall][.definecmds]") { Detector det; Caller caller(&det); auto det_type = det.getDetectorType().squash(); @@ -3356,7 +3356,7 @@ TEST_CASE("setbit", "[.cmdcall]") { } } -TEST_CASE("clearbit", "[.cmdcall]") { +TEST_CASE("clearbit", "[.cmdcall][.definecmds]") { Detector det; Caller caller(&det); auto det_type = det.getDetectorType().squash(); @@ -3386,7 +3386,7 @@ TEST_CASE("clearbit", "[.cmdcall]") { } } -TEST_CASE("getbit", "[.cmdcall]") { +TEST_CASE("getbit", "[.cmdcall][.definecmds]") { Detector det; Caller caller(&det); auto det_type = det.getDetectorType().squash(); diff --git a/slsDetectorSoftware/tests/test-CtbConfig.cpp b/slsDetectorSoftware/tests/test-CtbConfig.cpp index bb69fecdc..e5ef153e0 100644 --- a/slsDetectorSoftware/tests/test-CtbConfig.cpp +++ b/slsDetectorSoftware/tests/test-CtbConfig.cpp @@ -6,13 +6,16 @@ #include "CtbConfig.h" #include "SharedMemory.h" #include +#include namespace sls { TEST_CASE("Default construction") { - static_assert(sizeof(CtbConfig) == - (2 * sizeof(int) + (18 + 32 + 64 + 5 + 8) * 20), - "Size of CtbConfig does not match "); + /*TODO static_assert(sizeof(CtbConfig) == + (2 * sizeof(int) + (18 + 32 + 64 + 5 + 8) * 32) + + (sizeof(size_t) * 2) + ((sizeof(uint32_t) + 32) * 64) + + ((32 + sizeof(uint32_t) + sizeof(int)) * 64), "Size of CtbConfig does not + match "); //8952 (8696)*/ CtbConfig c; auto dacnames = c.getDacNames(); @@ -46,6 +49,16 @@ TEST_CASE("Default construction") { REQUIRE(sensenames[1] == "SLOWADC1"); REQUIRE(sensenames[2] == "SLOWADC2"); REQUIRE(sensenames[3] == "SLOWADC3"); + auto regisernames = c.getRegisterNames(); + REQUIRE(regisernames.size() == 0); + auto bitnames = c.getBitNames(); + REQUIRE(bitnames.size() == 0); + REQUIRE(c.getRegisterNamesCount() == 0); + auto registerNames = c.getRegisterNames(); + REQUIRE(registerNames.size() == 0); + REQUIRE(c.getBitNamesCount() == 0); + auto bitNames = c.getBitNames(); + REQUIRE(bitNames.size() == 0); } TEST_CASE("Set and get a single dac name") { @@ -85,4 +98,164 @@ TEST_CASE("Move CtbConfig ") { REQUIRE(c2.getDacName(3) == "yetanothername"); } +TEST_CASE("Add or modify a register name", "[.reg]") { + CtbConfig c; + auto addr = RegisterAddress(100); + auto addr1 = RegisterAddress(300); + + REQUIRE(c.getRegisterNamesCount() == 0); + REQUIRE_THROWS( + c.setRegisterName("reg1_with_a_really_long_name_to_crash", addr)); + // add an entry + REQUIRE_NOTHROW(c.setRegisterName("reg1", addr)); + REQUIRE(c.getRegisterName(addr) == "reg1"); + REQUIRE(c.getRegisterAddress("reg1") == addr); + REQUIRE(c.getRegisterNamesCount() == 1); + // modify an entry + REQUIRE_NOTHROW(c.setRegisterName("reg1", addr1)); + REQUIRE(c.getRegisterAddress("reg1") == addr1); + REQUIRE(c.getRegisterName(addr1) == "reg1"); + // clear all entries + REQUIRE_NOTHROW(c.clearRegisterNames()); + REQUIRE(c.getRegisterNamesCount() == 0); + REQUIRE_THROWS(c.getRegisterName(addr)); + REQUIRE_THROWS(c.getRegisterAddress("reg1")); + REQUIRE_THROWS(c.getRegisterName(addr1)); +} + +TEST_CASE("Add a register list", "[.reg]") { + CtbConfig c; + REQUIRE(c.getRegisterNamesCount() == 0); + + // add a list + std::map list = { + {"reg1", RegisterAddress(0x100)}, + {"reg2", RegisterAddress(0x200)}, + {"reg3", RegisterAddress(0x300)}}; + REQUIRE_NOTHROW(c.setRegisterNames(list)); + REQUIRE(c.getRegisterNamesCount() == static_cast(list.size())); + auto names = c.getRegisterNames(); + REQUIRE(names.size() == 3); + + // TODO std::set seen_values; + for (const auto &[key, val] : list) { + // check for duplicate keys, and key-value match + REQUIRE(names.count(key) == 1); + REQUIRE(names.at(key) == val); + + // check for duplicate values + // TODO REQUIRE(seen_values.count(val) == 0); + // TODO seen_values.insert(val); + } + + // clear all entries + REQUIRE_NOTHROW(c.clearRegisterNames()); + REQUIRE(c.getRegisterNames().size() == 0); +} + +TEST_CASE("Finding a regiser name or address", "[.reg]") { + CtbConfig c; + RegisterAddress addr1(0x100); + RegisterAddress addr2(0x200); + RegisterAddress addr3(0x300); + + // find nothing + REQUIRE(c.getRegisterNamesCount() == 0); + REQUIRE_THROWS(c.getRegisterName(addr1)); + REQUIRE_THROWS(c.getRegisterAddress("reg1")); + + std::map list = { + {"reg1", addr1}, {"reg2", addr2}, {"reg3", addr3}}; + REQUIRE_NOTHROW(c.setRegisterNames(list)); + + // find + REQUIRE(c.getRegisterName(addr1) == "reg1"); + REQUIRE(c.getRegisterName(addr2) == "reg2"); + REQUIRE(c.getRegisterAddress("reg3") == addr3); +} + +TEST_CASE("Add or modify a bit name", "[.reg]") { + CtbConfig c; + RegisterAddress addr(0x100); + BitAddress pos(addr, 2); + BitAddress pos1(addr, 5); + + REQUIRE(c.getBitNamesCount() == 0); + + REQUIRE_THROWS(c.setBitName("bit1_with_a_really_long_name_to_crash", + BitAddress(addr, 100))); + REQUIRE_THROWS(c.setBitName("bit1", BitAddress(addr, 32))); + REQUIRE_THROWS(c.setBitName("bit1", BitAddress(addr, -1))); + + // add an entry + REQUIRE_NOTHROW(c.setBitName("bit1", pos)); + REQUIRE(c.getBitName(pos) == "bit1"); + REQUIRE(c.getBitAddress("bit1") == pos); + REQUIRE(c.getBitNamesCount() == 1); + // modify an entry + REQUIRE_NOTHROW(c.setBitName("bit1", pos1)); + REQUIRE(c.getBitAddress("bit1") == pos1); + REQUIRE(c.getBitName(pos1) == "bit1"); + // clear all entries + REQUIRE_NOTHROW(c.clearBitNames()); + REQUIRE(c.getBitNamesCount() == 0); + REQUIRE_THROWS(c.getBitName(pos)); + REQUIRE_THROWS(c.getBitAddress("bit1")); + REQUIRE_THROWS(c.getBitName(pos1)); +} + +TEST_CASE("Add a bit list", "[.reg]") { + CtbConfig c; + REQUIRE(c.getBitNamesCount() == 0); + + RegisterAddress addr(0x100); + BitAddress pos1(addr, 2); + BitAddress pos2(addr, 21); + + BitAddress pos3(addr, 31); + + // add a list + std::map list = { + {"bit1", pos1}, {"bit2", pos2}, {"bit3", pos3}}; + REQUIRE_NOTHROW(c.setBitNames(list)); + REQUIRE(c.getBitNamesCount() == 3); + auto names = c.getBitNames(); + REQUIRE(names.size() == 3); + + // TODO std::set seen_values; + for (const auto &[key, val] : list) { + // check for duplicate keys, and key-value match + REQUIRE(names.count(key) == 1); + REQUIRE(names.at(key) == val); + + // check for duplicate values + // TODO REQUIRE(seen_values.count(val) == 0); + // TODO seen_values.insert(val); + } + + // clear all entries + REQUIRE_NOTHROW(c.clearBitNames()); + REQUIRE(c.getBitNames().size() == 0); +} + +TEST_CASE("Finding a bit value", "[.reg]") { + CtbConfig c; + RegisterAddress addr(0x100); + BitAddress pos(addr, 2); + BitAddress pos1(addr, 21); + BitAddress pos2(addr, 31); + + // find nothing + REQUIRE(c.getBitNamesCount() == 0); + REQUIRE_THROWS(c.getBitAddress("bit")); + + std::map list = { + {"bit0", pos}, {"bit1", pos1}, {"bit2", pos2}}; + REQUIRE_NOTHROW(c.setBitNames(list)); + + // find + REQUIRE(c.getBitAddress("bit2") == pos2); + REQUIRE(c.getBitName(pos1) == "bit1"); +} + } // namespace sls diff --git a/slsDetectorSoftware/tests/test-MapOnStack.cpp b/slsDetectorSoftware/tests/test-MapOnStack.cpp new file mode 100644 index 000000000..a0d996670 --- /dev/null +++ b/slsDetectorSoftware/tests/test-MapOnStack.cpp @@ -0,0 +1,133 @@ +#include "MapOnStack.h" +#include "catch.hpp" +#include "sls/bit_utils.h" + +#include + +namespace sls { + +using Key = FixedString<32>; + +TEST_CASE("MapOnStack with int values") { + MapOnStack map; + + map.addKey("bit0", 55); + map.addKeyOrSetValue("bit1", 66); + REQUIRE(map.size() == 2); + REQUIRE(map.capacity() == 64); + REQUIRE(map.empty() == false); + + REQUIRE(map.getValue("bit0") == 55); + REQUIRE(map.getValue("bit1") == 66); + + // Duplicate key throws + REQUIRE_THROWS(map.addKey("bit0", 77)); + // Duplicate value throws + REQUIRE_THROWS(map.addKey("bit2", 66)); + + // modifies + map.addKeyOrSetValue("bit0", 77); + REQUIRE(map.getValue("bit0") == 77); + + // containsKey / hasValue + REQUIRE(map.containsKey("bit1")); + REQUIRE(map.hasValue(77)); + + // Clear map + map.clear(); + REQUIRE(map.empty()); + REQUIRE(map.size() == 0); + REQUIRE(map.capacity() == 64); +} + +TEST_CASE("MapOnStack with BitAddress values") { + MapOnStack map; + + RegisterAddress addr0(0x100); + RegisterAddress addr1(0x200); + BitAddress b0(addr0, 0); + BitAddress b1(addr0, 1); + BitAddress b2(addr1, 0); + + map.addKey("bit0", b0); + map.addKeyOrSetValue("bit1", b1); + REQUIRE(map.size() == 2); + REQUIRE(map.capacity() == 64); + REQUIRE(map.empty() == false); + + REQUIRE(map.getValue("bit0") == b0); + REQUIRE(map.getValue("bit1") == b1); + + // Duplicate key throws + REQUIRE_THROWS(map.addKey("bit0", b2)); + // Duplicate value throws + REQUIRE_THROWS(map.addKey("bit2", b1)); + + // modifies + map.addKeyOrSetValue("bit0", b2); + REQUIRE(map.getValue("bit0") == b2); + + // containsKey / hasValue + REQUIRE(map.containsKey("bit1")); + REQUIRE(map.hasValue(b2)); + + // Clear map + map.clear(); + REQUIRE(map.empty()); + REQUIRE(map.size() == 0); + REQUIRE(map.capacity() == 64); +} + +TEST_CASE("Set and get a single entry") { + MapOnStack map; + RegisterAddress addr0(0x100); + + map.addKey("bit0", addr0); + auto entries = map.getMap(); + REQUIRE(entries.size() == 1); + + REQUIRE(map.getValue("bit0") == addr0); + REQUIRE(entries["bit0"] == addr0); +} + +TEST_CASE("Set a name that is too large throws") { + MapOnStack map; + REQUIRE_THROWS(map.addKey("somestringthatisreallytolongforadatac", 12)); +} + +TEST_CASE("Length of dac name cannot be 0") { + MapOnStack map; + REQUIRE_THROWS(map.addKey("", 12)); +} + +TEST_CASE("Copy a MapOnStack") { + MapOnStack m1; + m1.addKey("key1", 12); + + auto m2 = m1; + // change the first object + // to detecto shallow copy + m1.setValue("key1", 34); + REQUIRE(m2.getValue("key1") == 12); +} + +TEST_CASE("Move MapOnStack ") { + MapOnStack m1; + m1.addKey("key1", 12); + MapOnStack m2(std::move(m1)); + REQUIRE(m1.size() == 0); + REQUIRE(m2.size() == 1); +} + +TEST_CASE("Set map from std::map") { + MapOnStack map; + std::map m1 = {{"key1", 11}, {"key2", 22}, {"key3", 33}}; + map.setMap(m1); + REQUIRE(map.size() == 3); + REQUIRE(map.getValue("key2") == 22); + + auto retrieved_map = map.getMap(); + REQUIRE(retrieved_map.size() == 3); + REQUIRE(retrieved_map["key3"] == 33); + +} // namespace sls diff --git a/slsDetectorSoftware/tests/test-SharedMemory.cpp b/slsDetectorSoftware/tests/test-SharedMemory.cpp index c81f9643d..1f9355a4b 100644 --- a/slsDetectorSoftware/tests/test-SharedMemory.cpp +++ b/slsDetectorSoftware/tests/test-SharedMemory.cpp @@ -39,15 +39,13 @@ void freeShm(const int dindex, const int mIndex) { constexpr int shm_id = 10; -//macOS does not expose shm in the filesystem +// macOS does not expose shm in the filesystem #ifndef __APPLE__ const std::string file_path = std::string("/dev/shm/slsDetectorPackage_detector_") + std::to_string(shm_id); - - TEST_CASE("Free obsolete (without isValid)", "[detector][shm]") { // ensure its clean to start @@ -106,8 +104,8 @@ TEST_CASE("Create SharedMemory read and write", "[detector][shm]") { const char *env_p = std::getenv(SHM_ENV_NAME); std::string env_name = env_p ? ("_" + std::string(env_p)) : ""; - CHECK(shm.getName() == std::string(SHM_DETECTOR_PREFIX) + - std::to_string(shm_id) + env_name); + CHECK(shm.getName() == + std::string(SHM_DETECTOR_PREFIX) + std::to_string(shm_id) + env_name); shm()->x = 3; shm()->y = 5.7; strcpy_safe(shm()->mess, "Some string"); @@ -180,8 +178,8 @@ TEST_CASE("Move SharedMemory", "[detector][shm]") { std::string env_name = env_p ? ("_" + std::string(env_p)) : ""; SharedMemory shm(shm_id, -1); - CHECK(shm.getName() == std::string(SHM_DETECTOR_PREFIX) + - std::to_string(shm_id) + env_name); + CHECK(shm.getName() == + std::string(SHM_DETECTOR_PREFIX) + std::to_string(shm_id) + env_name); shm.createSharedMemory(); shm()->x = 9; @@ -191,8 +189,8 @@ TEST_CASE("Move SharedMemory", "[detector][shm]") { CHECK(shm2()->x == 9); REQUIRE_THROWS( shm()); // trying to access should throw instead of returning a nullptr - CHECK(shm2.getName() == std::string(SHM_DETECTOR_PREFIX) + - std::to_string(shm_id) + env_name); + CHECK(shm2.getName() == + std::string(SHM_DETECTOR_PREFIX) + std::to_string(shm_id) + env_name); shm2.removeSharedMemory(); } @@ -243,7 +241,8 @@ TEST_CASE("Create create a shared memory with a tag when SLSDETNAME is set") { setenv(SHM_ENV_NAME, "myprefix", 1); SharedMemory shm(0, -1, "ctbdacs"); - REQUIRE(shm.getName() == std::string(SHM_DETECTOR_PREFIX) + "0_myprefix_ctbdacs"); + REQUIRE(shm.getName() == + std::string(SHM_DETECTOR_PREFIX) + "0_myprefix_ctbdacs"); // Clean up after us if (old_slsdetname.empty()) diff --git a/slsReceiverSoftware/tests/test-Apps.cpp b/slsReceiverSoftware/tests/test-Apps.cpp index fbbd2ff96..98d186718 100644 --- a/slsReceiverSoftware/tests/test-Apps.cpp +++ b/slsReceiverSoftware/tests/test-Apps.cpp @@ -149,12 +149,11 @@ TEST_CASE("Parse port and uid", "[.failsongitea][detector]") { AppType::FrameSynchronizer}) { CommandLineOptions s(app); - // TODO! This test fails on gitea CI probably because the user can set the uid - // commenting it out for now. Revisit later. - // REQUIRE_THROWS( + // TODO! This test fails on gitea CI probably because the user can set + // the uid commenting it out for now. Revisit later. REQUIRE_THROWS( // s.parse({"", "-p", "1234", "-u", invalidUidStr})); // invalid uid - REQUIRE_THROWS(s.parse({"", "-p", "500"})); // invalid port + REQUIRE_THROWS(s.parse({"", "-p", "500"})); // invalid port auto opts = s.parse({"", "-p", "1234", "-u", uidStr}); std::visit( diff --git a/slsSupportLib/CMakeLists.txt b/slsSupportLib/CMakeLists.txt index f7480f2d5..995d24819 100755 --- a/slsSupportLib/CMakeLists.txt +++ b/slsSupportLib/CMakeLists.txt @@ -17,6 +17,7 @@ set(SOURCES src/sls_detector_exceptions.cpp src/md5_helper.cpp src/Version.cpp + src/bit_utils.cpp ) # Header files to install as a part of the library @@ -29,6 +30,7 @@ set(PUBLICHEADERS include/sls/ToString.h include/sls/TypeTraits.h include/sls/TimeHelper.h + include/sls/bit_utils.h ) # Additional headers to be installed if SLS_DEVEL_HEADERS diff --git a/slsSupportLib/include/sls/ToString.h b/slsSupportLib/include/sls/ToString.h index ea97a8436..5b56fbfc9 100644 --- a/slsSupportLib/include/sls/ToString.h +++ b/slsSupportLib/include/sls/ToString.h @@ -11,6 +11,7 @@ #include "sls/TimeHelper.h" #include "sls/TypeTraits.h" +#include "sls/bit_utils.h" #include "sls/sls_detector_defs.h" #include "sls/sls_detector_exceptions.h" #include "sls/string_utils.h" @@ -65,6 +66,7 @@ std::ostream &operator<<(std::ostream &os, std::string ToString(const slsDetectorDefs::pedestalParameters &r); std::ostream &operator<<(std::ostream &os, const slsDetectorDefs::pedestalParameters &r); + const std::string &ToString(const std::string &s); /** Convert std::chrono::duration with specified output unit */ @@ -324,6 +326,8 @@ template <> defs::gainMode StringTo(const std::string &s); template <> defs::polarity StringTo(const std::string &s); template <> defs::timingInfoDecoder StringTo(const std::string &s); template <> defs::collectionMode StringTo(const std::string &s); +template <> RegisterAddress StringTo(const std::string &s); +template <> RegisterValue StringTo(const std::string &s); template <> uint8_t StringTo(const std::string &s); template <> uint16_t StringTo(const std::string &s); diff --git a/slsSupportLib/include/sls/bit_utils.h b/slsSupportLib/include/sls/bit_utils.h index 164d1e3b8..af86a8462 100644 --- a/slsSupportLib/include/sls/bit_utils.h +++ b/slsSupportLib/include/sls/bit_utils.h @@ -3,6 +3,7 @@ #pragma once #include +#include #include namespace sls { template std::vector getSetBits(T val) { @@ -18,4 +19,87 @@ template std::vector getSetBits(T val) { } return set_bits; } + +class RegisterAddress { + private: + uint32_t value_{0}; + + public: + constexpr RegisterAddress() noexcept = default; + constexpr explicit RegisterAddress(uint32_t value) : value_(value) {} + std::string str() const; + constexpr uint32_t value() const noexcept { return value_; } + + constexpr bool operator==(const RegisterAddress &other) const { + return (value_ == other.value_); + } + constexpr bool operator!=(const RegisterAddress &other) const { + return (value_ != other.value_); + } +}; + +class BitAddress { + private: + RegisterAddress addr_{0}; + uint32_t bitPos_{0}; + + public: + constexpr BitAddress() noexcept = default; + BitAddress(RegisterAddress address, uint32_t bitPosition); + std::string str() const; + constexpr RegisterAddress address() const noexcept { return addr_; } + constexpr uint32_t bitPosition() const noexcept { return bitPos_; } + + constexpr bool operator==(const BitAddress &other) const { + return (addr_ == other.addr_ && bitPos_ == other.bitPos_); + } + constexpr bool operator!=(const BitAddress &other) const { + return !(*this == other); + } +}; + +class RegisterValue { + private: + uint32_t value_{0}; + + public: + constexpr RegisterValue() noexcept = default; + explicit constexpr RegisterValue(uint32_t value) noexcept : value_(value) {} + std::string str() const; + constexpr uint32_t value() const noexcept { return value_; } + + constexpr RegisterValue &operator|=(const RegisterValue &rhs) noexcept { + value_ |= rhs.value(); + return *this; + } + + constexpr RegisterValue operator|(const RegisterValue &rhs) const noexcept { + RegisterValue tmp(*this); + tmp |= rhs; + return tmp; + } + + constexpr RegisterValue &operator|=(uint32_t rhs) noexcept { + value_ |= rhs; + return *this; + } + + constexpr RegisterValue operator|(uint32_t rhs) const noexcept { + RegisterValue tmp(*this); + tmp |= rhs; + return tmp; + } + + constexpr bool operator==(const RegisterValue &other) const noexcept { + return value_ == other.value_; + } + constexpr bool operator!=(const RegisterValue &other) const noexcept { + return value_ != other.value_; + } +}; + +std::ostream &operator<<(std::ostream &os, const RegisterAddress &r); +std::ostream &operator<<(std::ostream &os, const BitAddress &r); +std::ostream &operator<<(std::ostream &os, const RegisterValue &r); + } // namespace sls diff --git a/slsSupportLib/include/sls/container_utils.h b/slsSupportLib/include/sls/container_utils.h index a3de80e40..13ac893f9 100644 --- a/slsSupportLib/include/sls/container_utils.h +++ b/slsSupportLib/include/sls/container_utils.h @@ -181,20 +181,18 @@ typename std::enable_if::value, bool>::type stableRemoveDuplicates(T &c) { auto containerSize = c.size(); std::set seen; - c.erase( - std::remove_if(c.begin(), c.end(), - [&](const typename T::value_type& val) { - return !seen.insert(val).second; // erase if already seen - }), - c.end() - ); + c.erase(std::remove_if( + c.begin(), c.end(), + [&](const typename T::value_type &val) { + return !seen.insert(val).second; // erase if already seen + }), + c.end()); if (c.size() != containerSize) { return true; } return false; } - } // namespace sls #endif // CONTAINER_UTILS_H diff --git a/slsSupportLib/include/sls/string_utils.h b/slsSupportLib/include/sls/string_utils.h index 86a5d0caf..dc1c037ac 100644 --- a/slsSupportLib/include/sls/string_utils.h +++ b/slsSupportLib/include/sls/string_utils.h @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -33,6 +34,35 @@ void strcpy_safe(char (&destination)[array_size], const std::string &source) { destination[array_size - 1] = '\0'; } +// Runtime-checked variant — throws if it won't fit +template +void strcpy_checked(char (&destination)[array_size], const char *source) { + if (!source) + throw std::runtime_error("Null source pointer in strcpy_checked"); + + size_t len = std::strlen(source); + if (len >= (array_size - 1)) { + throw std::runtime_error("String length (" + std::to_string(len) + + ") should be less than " + + std::to_string(array_size - 1) + " chars"); + } + std::strncpy(destination, source, array_size - 1); + destination[array_size - 1] = '\0'; +} + +template +void strcpy_checked(char (&destination)[array_size], + const std::string &source) { + if (source.size() >= (array_size - 1)) { + throw std::runtime_error("String length (" + + std::to_string(source.size()) + + ") should be less than " + + std::to_string(array_size - 1) + " chars"); + } + std::strncpy(destination, source.c_str(), array_size - 1); + destination[array_size - 1] = '\0'; +} + /* Removes all occurrences of the specified char from a c string Templated on array size to ensure no access after buffer limits. @@ -58,6 +88,8 @@ std::vector split(const std::string &strToSplit, char delimeter); std::string RemoveUnit(std::string &str); bool is_int(const std::string &s); +/** '0x200' is also an int here */ +bool is_hex_or_dec_uint(const std::string &s); bool replace_first(std::string *s, const std::string &substr, const std::string &repl); diff --git a/slsSupportLib/src/bit_utils.cpp b/slsSupportLib/src/bit_utils.cpp new file mode 100644 index 000000000..e0ce84cc0 --- /dev/null +++ b/slsSupportLib/src/bit_utils.cpp @@ -0,0 +1,42 @@ +// SPDX-License-Identifier: LGPL-3.0-or-other +// Copyright (C) 2021 Contributors to the SLS Detector Package +#include "sls/bit_utils.h" +#include "sls/ToString.h" +#include "sls/sls_detector_exceptions.h" + +namespace sls { + +std::string RegisterAddress::str() const { return ToStringHex(value_); } + +BitAddress::BitAddress(RegisterAddress address, uint32_t bitPosition) + : addr_(address) { + if (bitPosition > 31) { + throw RuntimeError("Bit position must be between 0 and 31."); + } + bitPos_ = bitPosition; +} + +std::string BitAddress::str() const { + std::ostringstream os; + os << '[' << addr_.str() << ", " << ToString(bitPos_) << ']'; + return os.str(); +} + +std::string RegisterValue::str() const { return ToStringHex(value_); } + +std::ostream &operator<<(std::ostream &os, const RegisterAddress &r) { + os << r.str(); + return os; +} + +std::ostream &operator<<(std::ostream &os, const BitAddress &r) { + os << r.str(); + return os; +} + +std::ostream &operator<<(std::ostream &os, const RegisterValue &r) { + os << r.str(); + return os; +} + +} // namespace sls diff --git a/slsSupportLib/src/file_utils.cpp b/slsSupportLib/src/file_utils.cpp index 3b82a5a9f..6751d489d 100644 --- a/slsSupportLib/src/file_utils.cpp +++ b/slsSupportLib/src/file_utils.cpp @@ -256,24 +256,22 @@ std::string getAbsolutePathFromCurrentProcess(const std::string &fname) { return fname; } - //in case PATH_MAX defines the longest possible path on linux and macOS - //use string instead of char array to avoid overflow - std::string path(PATH_MAX, '\0'); + // in case PATH_MAX defines the longest possible path on linux and macOS + // use string instead of char array to avoid overflow + std::string path(PATH_MAX, '\0'); - - #if defined(__APPLE__) +#if defined(__APPLE__) uint32_t size = PATH_MAX; if (_NSGetExecutablePath(path.data(), &size) != 0) { throw std::runtime_error("Failed to get executable path"); } // Resolve any symlinks and .. components - std::string resolved(PATH_MAX, '\0'); + std::string resolved(PATH_MAX, '\0'); if (!realpath(path.data(), resolved.data())) { throw std::runtime_error("realpath failed for executable"); } path = resolved; - #else - +#else ssize_t len = readlink("/proc/self/exe", path.data(), PATH_MAX - 1); if (len < 0) { @@ -281,7 +279,7 @@ std::string getAbsolutePathFromCurrentProcess(const std::string &fname) { } path[len] = '\0'; - #endif +#endif // get dir path and attach file name std::string absPath = (std::string(dirname(path.data())) + '/' + fname); diff --git a/slsSupportLib/src/network_utils.cpp b/slsSupportLib/src/network_utils.cpp index 166d9ccf0..c8f92732d 100644 --- a/slsSupportLib/src/network_utils.cpp +++ b/slsSupportLib/src/network_utils.cpp @@ -179,8 +179,7 @@ IpAddr InterfaceNameToIp(const std::string &ifn) { MacAddr InterfaceNameToMac(const std::string &inf) { #ifdef __APPLE__ - throw RuntimeError( - "InterfaceNameToMac not implemented on macOS yet"); + throw RuntimeError("InterfaceNameToMac not implemented on macOS yet"); #else // TODO! Copied from genericSocket needs to be refactored! diff --git a/slsSupportLib/src/string_utils.cpp b/slsSupportLib/src/string_utils.cpp index 0ed191685..1426049ff 100644 --- a/slsSupportLib/src/string_utils.cpp +++ b/slsSupportLib/src/string_utils.cpp @@ -43,6 +43,15 @@ bool is_int(const std::string &s) { }) == s.end(); } +bool is_hex_or_dec_uint(const std::string &s) { + try { + StringTo(s); + return true; + } catch (...) { + } + return false; +} + bool replace_first(std::string *s, const std::string &substr, const std::string &repl) { auto pos = s->find(substr); diff --git a/slsSupportLib/tests/test-UdpRxSocket.cpp b/slsSupportLib/tests/test-UdpRxSocket.cpp index 645fed8c1..7cbee5e29 100644 --- a/slsSupportLib/tests/test-UdpRxSocket.cpp +++ b/slsSupportLib/tests/test-UdpRxSocket.cpp @@ -84,8 +84,8 @@ TEST_CASE("Shutdown socket without hanging when waiting for data") { // Start a thread and wait for package // if the socket is left open we would block - std::future ret = - std::async(std::launch::async, &UdpRxSocket::ReceivePacket, &s, (char *)&buff); + std::future ret = std::async( + std::launch::async, &UdpRxSocket::ReceivePacket, &s, (char *)&buff); s.Shutdown(); auto r = ret.get(); diff --git a/slsSupportLib/tests/test-bit_utils.cpp b/slsSupportLib/tests/test-bit_utils.cpp index 9217f9ec0..713e1c2ce 100644 --- a/slsSupportLib/tests/test-bit_utils.cpp +++ b/slsSupportLib/tests/test-bit_utils.cpp @@ -2,6 +2,7 @@ // Copyright (C) 2021 Contributors to the SLS Detector Package #include "catch.hpp" #include "sls/bit_utils.h" +#include #include namespace sls { @@ -42,4 +43,108 @@ TEST_CASE("Get set bits from 523") { REQUIRE(vec == std::vector{0, 1, 3, 9}); } +TEST_CASE("Convert RegisterAddress using classes ", "[support][.bit_utils]") { + std::vector vec_addr{0x305, 0xffffffff, 0x0, 0x34550987, + 0x1fff1fff}; + std::vector vec_ans{"0x305", "0xffffffff", "0x0", "0x34550987", + "0x1fff1fff"}; + + for (size_t i = 0; i != vec_addr.size(); ++i) { + auto reg0 = RegisterAddress(vec_addr[i]); + auto reg1 = RegisterAddress(vec_addr[i]); + auto reg2 = RegisterAddress(vec_addr[0]); + + CHECK(reg0 == reg1); + if (i != 0) + CHECK(reg2 != reg1); + CHECK(reg0.value() == vec_addr[i]); + CHECK(reg1.value() == vec_addr[i]); + CHECK(reg0.str() == vec_ans[i]); + CHECK(reg1.str() == vec_ans[i]); + } +} + +TEST_CASE("Convert RegisterValue using classes ", "[support][.bit_utils]") { + std::vector vec_addr{0x305, 0xffffffff, 0x0, 500254562, + 0x1fff1fff}; + std::vector vec_ans{"0x305", "0xffffffff", "0x0", "0x1dd14762", + "0x1fff1fff"}; + + for (size_t i = 0; i != vec_addr.size(); ++i) { + auto reg0 = RegisterValue(vec_addr[i]); + auto reg2 = RegisterValue(vec_addr[0]); + + if (i != 0) + CHECK(reg2 != reg0); + CHECK(reg0.value() == vec_addr[i]); + CHECK(reg0.str() == vec_ans[i]); + CHECK((reg0 | 0xffffffffu) == RegisterValue(0xffffffffu)); + CHECK((reg0 | 0x0) == reg0); + CHECK((reg0 | 0x1) == reg0); + } +} + +TEST_CASE("Convert BitAddress using classes", "[support][.bit_utils]") { + std::vector vec_addr{ + RegisterAddress(0x305), RegisterAddress(0xffffffffu), + RegisterAddress(0x0), RegisterAddress(0x34550987), + RegisterAddress(0x1fff1fff)}; + std::vector vec_addr_str{"0x305", "0xffffffff", "0x0", + "0x34550987", "0x1fff1fff"}; + std::vector vec_bitpos{0, 15, 31, 7, 23}; + std::vector vec_bitpos_str{"0", "15", "31", "7", "23"}; + std::vector vec_ans{ + "[0x305, 0]", "[0xffffffff, 15]", "[0x0, 31]", + "[0x34550987, 7]", "[0x1fff1fff, 23]", + }; + + for (size_t i = 0; i != vec_addr.size(); ++i) { + auto reg0 = BitAddress(vec_addr[i], vec_bitpos[i]); + + BitAddress reg1(vec_addr[i], vec_bitpos[i]); + CHECK(reg1.address() == vec_addr[i]); + CHECK(reg1.bitPosition() == vec_bitpos[i]); + + auto reg2 = BitAddress(vec_addr[0], vec_bitpos[0]); + + CHECK(reg0 == reg1); + if (i != 0) + CHECK(reg2 != reg1); + CHECK(reg0.address() == vec_addr[i]); + CHECK(reg1.address() == vec_addr[i]); + CHECK(reg0.bitPosition() == vec_bitpos[i]); + CHECK(reg1.bitPosition() == vec_bitpos[i]); + CHECK(std::to_string(reg0.bitPosition()) == vec_bitpos_str[i]); + CHECK(std::to_string(reg1.bitPosition()) == vec_bitpos_str[i]); + + CHECK(reg0.str() == vec_ans[i]); + CHECK(reg1.str() == vec_ans[i]); + } +} + +TEST_CASE("Output operator gives same result as string", + "[support][.bit_utils]") { + { + RegisterAddress addr{0x3456af}; + std::ostringstream os; + os << addr; + CHECK(os.str() == "0x3456af"); + CHECK(os.str() == addr.str()); + } + { + BitAddress addr{RegisterAddress(0x3456af), 15}; + std::ostringstream os; + os << addr; + CHECK(os.str() == "[0x3456af, 15]"); + CHECK(os.str() == addr.str()); + } + { + RegisterValue addr{0x3456af}; + std::ostringstream os; + os << addr; + CHECK(os.str() == "0x3456af"); + CHECK(os.str() == addr.str()); + } +} + } // namespace sls diff --git a/slsSupportLib/tests/test-container_utils.cpp b/slsSupportLib/tests/test-container_utils.cpp index b43eaf814..e546662bb 100644 --- a/slsSupportLib/tests/test-container_utils.cpp +++ b/slsSupportLib/tests/test-container_utils.cpp @@ -175,13 +175,12 @@ TEST_CASE("remove duplicates but keep order, all elements the same ") { } TEST_CASE("remove duplicates but keep order, pattern ") { - std::vector v{8,1,2,8,8,3,2}; + std::vector v{8, 1, 2, 8, 8, 3, 2}; auto r = stableRemoveDuplicates(v); CHECK(r == true); // did indeed remove elements - CHECK(v == std::vector{8,1,2,3}); + CHECK(v == std::vector{8, 1, 2, 3}); } - TEST_CASE("remove duplicated empty vector") { std::vector v; auto r = removeDuplicates(v); diff --git a/tests/scripts/utils_for_test.py b/tests/scripts/utils_for_test.py index f73e819b8..bff86f886 100644 --- a/tests/scripts/utils_for_test.py +++ b/tests/scripts/utils_for_test.py @@ -63,26 +63,30 @@ def checkIfProcessRunning(processName): def killProcess(name, fp): - pids = checkIfProcessRunning(name) - if pids: - Log(LogLevel.INFO, f"Killing '{name}' processes with PIDs: {', '.join(pids)}", fp) - for pid in pids: - try: - p = subprocess.run(['kill', pid]) - if p.returncode != 0 and bool(checkIfProcessRunning(name)): - raise RuntimeException(f"Could not kill {name} with pid {pid}") - except Exception as e: - raise RuntimeException(f"Failed to kill process {name} pid:{pid}. Error: {str(e)}") from e - #else: - # Log(LogLevel.INFO, 'process not running : ' + name) + ''' + Kill all processes matching name. + Does not fail if process is already gone. + ''' + Log(LogLevel.INFO, f"Attempting to kill '{name}' (if running)", fp) + + # pkill returns: + # 0 -> process killed + # 1 -> no process found OK + subprocess.run(['pkill', '-f', name], + stdout=subprocess.DEVNULL, + stderr=subprocess.DEVNULL) def cleanSharedmemory(fp): Log(LogLevel.INFO, 'Cleaning up shared memory', fp) try: - p = subprocess.run(['sls_detector_get', 'free'], stdout=fp, stderr=fp) - except: - raise RuntimeException('Could not free shared memory') + p = subprocess.run(['sls_detector_get', 'free'], stdout=fp, stderr=fp, check = False) + except FileNotFoundError: + # Binary not available (e.g. on CI) → ignore + Log(LogLevel.INFO, 'sls_detector_get not found, skipping shared memory cleanup', fp) + except Exception as e: + # Any other cleanup failure should NEVER fail tests + Log(LogLevel.WARN, f'Ignoring shared memory cleanup error: {e}', fp) def cleanup(fp):