diff --git a/python/slsdet/ctb.py b/python/slsdet/ctb.py index 10afd3ae3..53ba8e8d7 100644 --- a/python/slsdet/ctb.py +++ b/python/slsdet/ctb.py @@ -1,43 +1,45 @@ # SPDX-License-Identifier: LGPL-3.0-or-other # Copyright (C) 2021 Contributors to the SLS Detector Package -from .detector import Detector +from .detector import Detector, freeze from .utils import element_if_equal -from .dacs import DetectorDacs +from .dacs import DetectorDacs, NamedDacs import _slsdet dacIndex = _slsdet.slsDetectorDefs.dacIndex from .detector_property import DetectorProperty -class CtbDacs(DetectorDacs): - """ - Ctb dacs - """ - _dacs = [('dac0', dacIndex(0), 0, 4000, 1400), - ('dac1', dacIndex(1), 0, 4000, 1200), - ('dac2', dacIndex(2), 0, 4000, 900), - ('dac3', dacIndex(3), 0, 4000, 1050), - ('dac4', dacIndex(4), 0, 4000, 1400), - ('dac5', dacIndex(5), 0, 4000, 655), - ('dac6', dacIndex(6), 0, 4000, 2000), - ('dac7', dacIndex(7), 0, 4000, 1400), - ('dac8', dacIndex(8), 0, 4000, 850), - ('dac9', dacIndex(9), 0, 4000, 2000), - ('dac10', dacIndex(10), 0, 4000, 2294), - ('dac11', dacIndex(11), 0, 4000, 983), - ('dac12', dacIndex(12), 0, 4000, 1475), - ('dac13', dacIndex(13), 0, 4000, 1200), - ('dac14', dacIndex(14), 0, 4000, 1600), - ('dac15', dacIndex(15), 0, 4000, 1455), - ('dac16', dacIndex(16), 0, 4000, 0), - ('dac17', dacIndex(17), 0, 4000, 1000), - ] - _dacnames = [_d[0] for _d in _dacs] +# class CtbDacs(DetectorDacs): +# """ +# Ctb dacs +# """ +# _dacs = [('dac0', dacIndex(0), 0, 4000, 1400), +# ('dac1', dacIndex(1), 0, 4000, 1200), +# ('dac2', dacIndex(2), 0, 4000, 900), +# ('dac3', dacIndex(3), 0, 4000, 1050), +# ('dac4', dacIndex(4), 0, 4000, 1400), +# ('dac5', dacIndex(5), 0, 4000, 655), +# ('dac6', dacIndex(6), 0, 4000, 2000), +# ('dac7', dacIndex(7), 0, 4000, 1400), +# ('dac8', dacIndex(8), 0, 4000, 850), +# ('dac9', dacIndex(9), 0, 4000, 2000), +# ('dac10', dacIndex(10), 0, 4000, 2294), +# ('dac11', dacIndex(11), 0, 4000, 983), +# ('dac12', dacIndex(12), 0, 4000, 1475), +# ('dac13', dacIndex(13), 0, 4000, 1200), +# ('dac14', dacIndex(14), 0, 4000, 1600), +# ('dac15', dacIndex(15), 0, 4000, 1455), +# ('dac16', dacIndex(16), 0, 4000, 0), +# ('dac17', dacIndex(17), 0, 4000, 1000), +# ] +# _dacnames = [_d[0] for _d in _dacs] from .utils import element +@freeze class Ctb(Detector): def __init__(self, id = 0): super().__init__(id) self._frozen = False - self._dacs = CtbDacs(self) + # self._dacs = CtbDacs(self) + self._dacs = NamedDacs(self) @property def dacs(self): diff --git a/python/slsdet/dacs.py b/python/slsdet/dacs.py index 7b454e783..0321c24dc 100755 --- a/python/slsdet/dacs.py +++ b/python/slsdet/dacs.py @@ -36,6 +36,79 @@ class Dac(DetectorProperty): dacstr = ''.join([f'{item:5d}' for item in self.get()]) return f'{self.__name__:15s}:{dacstr}' +class NamedDacs: + """ + New implementation of the detector dacs. Used at the momen for + Ctb but should replace the old one for all detectors + """ + _frozen = False + _direct_access = ['_detector', '_current', '_dacnames'] + def __init__(self, detector): + self._detector = detector + self._current = 0 + + self._dacnames = [n.replace(" ", "") for n in detector.getDacNames()] + # # Populate the dacs + for i,name in enumerate(self._dacnames): + #name, enum, low, high, default, detector + setattr(self, name, Dac(name, dacIndex(i), 0, 4000, 1000, detector)) + + self._frozen = True + + # def __getattr__(self, name): + # return self.__getattribute__('_' + name) + + def __setattr__(self, name, value): + if not self._frozen: + #durining init we need to be able to set up the class + super().__setattr__(name, value) + else: + #Later we restrict us to manipulate dacs and a few fields + if name in self._direct_access: + super().__setattr__(name, value) + elif name in self._dacnames: + return self.__getattribute__(name).__setitem__(slice(None, None, None), value) + else: + raise AttributeError(f'Dac not found: {name}') + + def __next__(self): + if self._current >= len(self._dacnames): + self._current = 0 + raise StopIteration + else: + self._current += 1 + return self.__getattribute__(self._dacnames[self._current-1]) + # return self.__getattr__(self._dacnames[self._current-1]) + + def __iter__(self): + return self + + def __repr__(self): + r_str = ['========== DACS ========='] + r_str += [repr(dac) for dac in self] + return '\n'.join(r_str) + def get_asarray(self): + """ + Read the dacs into a numpy array with dimensions [ndacs, nmodules] + """ + dac_array = np.zeros((len(self._dacnames), len(self._detector))) + for i, _d in enumerate(self): + dac_array[i,:] = _d[:] + return dac_array + + def to_array(self): + return self.get_asarray() + + def set_from_array(self, dac_array): + """ + Set the dacs from an numpy array with dac values. [ndacs, nmodules] + """ + dac_array = dac_array.astype(np.int) + for i, _d in enumerate(self): + _d[:] = dac_array[i] + + def from_array(self, dac_array): + self.set_from_array(dac_array) class DetectorDacs: _dacs = [] @@ -50,7 +123,7 @@ class DetectorDacs: # Index to support iteration self._current = 0 - # Populate the dacs + # Name the attributes? for _d in self._dacs: setattr(self, '_'+_d[0], Dac(*_d, detector)) diff --git a/slsDetectorSoftware/CMakeLists.txt b/slsDetectorSoftware/CMakeLists.txt index ce88e0ca8..e5589dccc 100755 --- a/slsDetectorSoftware/CMakeLists.txt +++ b/slsDetectorSoftware/CMakeLists.txt @@ -7,6 +7,7 @@ set(SOURCES src/CmdProxy.cpp src/CmdParser.cpp src/Pattern.cpp + src/ctb_named_dacs.cpp ) add_library(slsDetectorObject OBJECT diff --git a/slsDetectorSoftware/src/Detector.cpp b/slsDetectorSoftware/src/Detector.cpp index 7bc8347cb..8ad11ce82 100644 --- a/slsDetectorSoftware/src/Detector.cpp +++ b/slsDetectorSoftware/src/Detector.cpp @@ -7,6 +7,7 @@ #include "CmdProxy.h" #include "DetectorImpl.h" #include "Module.h" +#include "ctb_named_dacs.h" #include "sls/Pattern.h" #include "sls/container_utils.h" #include "sls/file_utils.h" @@ -21,6 +22,9 @@ namespace sls { void freeSharedMemory(int detectorIndex, int moduleIndex) { + // + remove_ctb_dacnames(detectorIndex); + // single module if (moduleIndex >= 0) { SharedMemory moduleShm(detectorIndex, moduleIndex); @@ -54,7 +58,10 @@ Detector::Detector(int shm_id) Detector::~Detector() = default; // Configuration -void Detector::freeSharedMemory() { pimpl->freeSharedMemory(); } +void Detector::freeSharedMemory() { + remove_ctb_dacnames(pimpl->getDetectorIndex()); + pimpl->freeSharedMemory(); +} void Detector::loadConfig(const std::string &fname) { int shm_id = getShmId(); @@ -2070,47 +2077,19 @@ void Detector::setLEDEnable(bool enable, Positions pos) { void Detector::setDacNames(const std::vector names) { if (getDetectorType().squash() != defs::CHIPTESTBOARD) throw RuntimeError("Named dacs only for CTB"); - if (names.size() != 18) - throw RuntimeError("Need to set all 18 dacs when naming dacs"); - - std::ofstream ofs("/dev/shm/slsDetectorPackage_ctbdacnames"); - if (!ofs) - throw RuntimeError("Failed to open dacnames file in shared memory"); - - std::string s = sls::ToString(names); - ofs.write(&s[0], s.size()); + set_ctb_dac_names(names, pimpl->getDetectorIndex()); } std::vector Detector::getDacNames() const { - + std::vector names; auto type = getDetectorType().squash(); if (type == defs::CHIPTESTBOARD) { - try { - std::ifstream ifs("/dev/shm/slsDetectorPackage_ctbdacnames"); - if (!ifs) - throw RuntimeError("Could not read dacnames form shm"); - std::string dacnames; - ifs.seekg(0, std::ios::end); - dacnames.resize(ifs.tellg()); - ifs.seekg(0, std::ios::beg); - ifs.read(&dacnames[0], dacnames.size()); - - std::string chars = "[] "; - - dacnames.erase(std::remove_if(dacnames.begin(), dacnames.end(), - [&chars](const char &c) { - return chars.find(c) != - std::string::npos; - }), - dacnames.end()); - auto names = sls::split(dacnames, ','); - return names; - } catch (...) { - } + names = get_ctb_dac_names(pimpl->getDetectorIndex()); + } + if (names.empty()) { + for (const auto &index : getDacList()) + names.push_back(ToString(index)); } - std::vector names; - for (const auto& index : getDacList()) - names.push_back(ToString(index)); return names; } diff --git a/slsDetectorSoftware/src/ctb_named_dacs.cpp b/slsDetectorSoftware/src/ctb_named_dacs.cpp new file mode 100644 index 000000000..9bea69984 --- /dev/null +++ b/slsDetectorSoftware/src/ctb_named_dacs.cpp @@ -0,0 +1,65 @@ + +#include "SharedMemory.h" +#include "ctb_named_dacs.h" +#include "sls/string_utils.h" +#include "sls/ToString.h" + +#include +#include +#include + +namespace sls { + +std::vector get_ctb_dac_names(int det_id) { + std::ifstream ifs(ctb_dac_fname(det_id)); + if (!ifs) + return {}; + + std::string dacnames; + ifs.seekg(0, std::ios::end); + dacnames.resize(ifs.tellg()); + ifs.seekg(0, std::ios::beg); + ifs.read(&dacnames[0], dacnames.size()); + + std::string chars = "[] "; + + dacnames.erase(std::remove_if(dacnames.begin(), dacnames.end(), + [&chars](const char &c) { + return chars.find(c) != std::string::npos; + }), + dacnames.end()); + auto names = sls::split(dacnames, ','); + return names; +} + +std::string ctb_dac_fname(int det_id) { + std::string sEnvPath; + char *envpath = getenv(SHM_ENV_NAME); + if (envpath != nullptr) { + sEnvPath.assign(envpath); + sEnvPath.append("_"); + } + sEnvPath.insert(0, "_"); + std::stringstream oss; + oss << "/dev/shm" << SHM_DETECTOR_PREFIX << det_id << sEnvPath << "ctbdacs"; + return oss.str(); +} + +void set_ctb_dac_names(const std::vector& names, int det_id){ + if (names.size() != 18) + throw RuntimeError("Need to set all 18 dacs when naming dacs"); + + + std::ofstream ofs(ctb_dac_fname(det_id)); + if(!ofs) + throw RuntimeError("Could not open dacnames file for writing"); + std::string s = sls::ToString(names); + ofs.write(&s[0], s.size()); +} + + +void remove_ctb_dacnames(int det_id){ + unlink(ctb_dac_fname(det_id).c_str()); +} + +} // namespace sls \ No newline at end of file diff --git a/slsDetectorSoftware/src/ctb_named_dacs.h b/slsDetectorSoftware/src/ctb_named_dacs.h new file mode 100644 index 000000000..30b5c470f --- /dev/null +++ b/slsDetectorSoftware/src/ctb_named_dacs.h @@ -0,0 +1,13 @@ +#pragma once +#include +#include +namespace sls{ + +std::vector get_ctb_dac_names(int det_id); +void set_ctb_dac_names(const std::vector& names, int det_id); +std::string ctb_dac_fname(int det_id); +void remove_ctb_dacnames(int det_id); + + +} + diff --git a/slsDetectorSoftware/tests/CMakeLists.txt b/slsDetectorSoftware/tests/CMakeLists.txt index bc65a73e9..c54b13c24 100755 --- a/slsDetectorSoftware/tests/CMakeLists.txt +++ b/slsDetectorSoftware/tests/CMakeLists.txt @@ -18,6 +18,7 @@ target_sources(tests PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/test-CmdParser.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test-Module.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test-Pattern.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/test_ctb_named_dacs.cpp ) target_include_directories(tests PUBLIC "$") \ No newline at end of file diff --git a/slsDetectorSoftware/tests/test-CmdProxy.cpp b/slsDetectorSoftware/tests/test-CmdProxy.cpp index 06b95c48f..ff451bff5 100644 --- a/slsDetectorSoftware/tests/test-CmdProxy.cpp +++ b/slsDetectorSoftware/tests/test-CmdProxy.cpp @@ -590,13 +590,13 @@ TEST_CASE("master", "[.cmd]") { } { std::ostringstream oss1; - proxy.Call("master", {"0"}, 0, PUT, oss3); - REQUIRE(oss3.str() == "master 0\n"); + proxy.Call("master", {"0"}, 0, PUT, oss1); + REQUIRE(oss1.str() == "master 0\n"); } { std::ostringstream oss1; - proxy.Call("master", {"1"}, 0, PUT, oss3); - REQUIRE(oss3.str() == "master 1\n"); + proxy.Call("master", {"1"}, 0, PUT, oss1); + REQUIRE(oss1.str() == "master 1\n"); } REQUIRE_THROWS(proxy.Call("master", {"1"}, -1, PUT)); // set all to slaves, and then master diff --git a/slsDetectorSoftware/tests/test_ctb_named_dacs.cpp b/slsDetectorSoftware/tests/test_ctb_named_dacs.cpp new file mode 100644 index 000000000..6080a33d0 --- /dev/null +++ b/slsDetectorSoftware/tests/test_ctb_named_dacs.cpp @@ -0,0 +1,61 @@ +#include "catch.hpp" +#include + +#include + +#include "SharedMemory.h" +#include "ctb_named_dacs.h" +using namespace sls; +#include +TEST_CASE("Create name for shm dac file") { + // if SLSDETNAME is already set we unset it but + // save the value + std::string old_slsdetname; + if (getenv(SHM_ENV_NAME)) + old_slsdetname = getenv(SHM_ENV_NAME); + unsetenv(SHM_ENV_NAME); + + int det_id = 0; + REQUIRE(ctb_dac_fname(det_id) == "/dev/shm/slsDetectorPackage_detector_0_ctbdacs"); + + setenv(SHM_ENV_NAME, "myprefix", 1); + REQUIRE(ctb_dac_fname(det_id) == + "/dev/shm/slsDetectorPackage_detector_0_myprefix_ctbdacs"); + + // Clean up after us + if (old_slsdetname.empty()) + unsetenv(SHM_ENV_NAME); + else + setenv(SHM_ENV_NAME, old_slsdetname.c_str(), 1); +} + +TEST_CASE("Get ctb dac names returns an empty vector when not set"){ + int large_unlikely_number = 123203; + auto vec = get_ctb_dac_names(large_unlikely_number); + REQUIRE(vec.empty()); +} + +TEST_CASE("Remove file fails silently when file is not present"){ + int large_unlikely_number = 123203; + REQUIRE_NOTHROW(remove_ctb_dacnames(large_unlikely_number)); +} + +TEST_CASE("Read dacs from file then remove file"){ + int large_unlikely_number = 998765; + std::ofstream out(ctb_dac_fname(large_unlikely_number)); + std::string names = "[first, second, third]"; + out.write(&names[0], names.size()); + out.close(); + + auto dacnames = get_ctb_dac_names(large_unlikely_number); + REQUIRE(dacnames.size() == 3); + REQUIRE(dacnames[0] == "first"); + REQUIRE(dacnames[1] == "second"); + REQUIRE(dacnames[2] == "third"); + + remove_ctb_dacnames(large_unlikely_number); + + std::ifstream in(ctb_dac_fname(large_unlikely_number)); + REQUIRE_FALSE(in); + +} \ No newline at end of file