Setting dac names for CTB (C++ and Python) (#413)

# Setting DAC names for CTB
* Introduced new shared memory for CTB only
* Prepared for additional functionality 
* Works from C++ and Python

Co-authored-by: Dhanya Thattil <dhanya.thattil@psi.ch>
This commit is contained in:
Erik Fröjdh 2022-03-28 14:27:47 +02:00 committed by GitHub
parent fc41d4313f
commit 1ff35edb99
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 487 additions and 67 deletions

View File

@ -54,7 +54,7 @@ This document describes the differences between v7.0.0 and v6.x.x
- added geometry to metadata - added geometry to metadata
- 10g eiger nextframenumber get fixed. - 10g eiger nextframenumber get fixed.
- stop, able to set nextframenumber to a consistent (max + 1) for all modules if different (eiger/ctb/jungfrau/moench) - stop, able to set nextframenumber to a consistent (max + 1) for all modules if different (eiger/ctb/jungfrau/moench)
- fpga/kernel programming, checks if drive is a special file and not a normal file - ctb: can set names for all the dacs
- fpga/kernel programming, checks if drive is a special file and not a normal file - fpga/kernel programming, checks if drive is a special file and not a normal file
- gotthard 25 um image reconstructed in gui and virtual hdf5 (firmware updated for slave to reverse channels) - gotthard 25 um image reconstructed in gui and virtual hdf5 (firmware updated for slave to reverse channels)

View File

@ -1,43 +1,45 @@
# SPDX-License-Identifier: LGPL-3.0-or-other # SPDX-License-Identifier: LGPL-3.0-or-other
# Copyright (C) 2021 Contributors to the SLS Detector Package # 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 .utils import element_if_equal
from .dacs import DetectorDacs from .dacs import DetectorDacs, NamedDacs
import _slsdet import _slsdet
dacIndex = _slsdet.slsDetectorDefs.dacIndex dacIndex = _slsdet.slsDetectorDefs.dacIndex
from .detector_property import DetectorProperty from .detector_property import DetectorProperty
class CtbDacs(DetectorDacs): # class CtbDacs(DetectorDacs):
""" # """
Ctb dacs # Ctb dacs
""" # """
_dacs = [('dac0', dacIndex(0), 0, 4000, 1400), # _dacs = [('dac0', dacIndex(0), 0, 4000, 1400),
('dac1', dacIndex(1), 0, 4000, 1200), # ('dac1', dacIndex(1), 0, 4000, 1200),
('dac2', dacIndex(2), 0, 4000, 900), # ('dac2', dacIndex(2), 0, 4000, 900),
('dac3', dacIndex(3), 0, 4000, 1050), # ('dac3', dacIndex(3), 0, 4000, 1050),
('dac4', dacIndex(4), 0, 4000, 1400), # ('dac4', dacIndex(4), 0, 4000, 1400),
('dac5', dacIndex(5), 0, 4000, 655), # ('dac5', dacIndex(5), 0, 4000, 655),
('dac6', dacIndex(6), 0, 4000, 2000), # ('dac6', dacIndex(6), 0, 4000, 2000),
('dac7', dacIndex(7), 0, 4000, 1400), # ('dac7', dacIndex(7), 0, 4000, 1400),
('dac8', dacIndex(8), 0, 4000, 850), # ('dac8', dacIndex(8), 0, 4000, 850),
('dac9', dacIndex(9), 0, 4000, 2000), # ('dac9', dacIndex(9), 0, 4000, 2000),
('dac10', dacIndex(10), 0, 4000, 2294), # ('dac10', dacIndex(10), 0, 4000, 2294),
('dac11', dacIndex(11), 0, 4000, 983), # ('dac11', dacIndex(11), 0, 4000, 983),
('dac12', dacIndex(12), 0, 4000, 1475), # ('dac12', dacIndex(12), 0, 4000, 1475),
('dac13', dacIndex(13), 0, 4000, 1200), # ('dac13', dacIndex(13), 0, 4000, 1200),
('dac14', dacIndex(14), 0, 4000, 1600), # ('dac14', dacIndex(14), 0, 4000, 1600),
('dac15', dacIndex(15), 0, 4000, 1455), # ('dac15', dacIndex(15), 0, 4000, 1455),
('dac16', dacIndex(16), 0, 4000, 0), # ('dac16', dacIndex(16), 0, 4000, 0),
('dac17', dacIndex(17), 0, 4000, 1000), # ('dac17', dacIndex(17), 0, 4000, 1000),
] # ]
_dacnames = [_d[0] for _d in _dacs] # _dacnames = [_d[0] for _d in _dacs]
from .utils import element from .utils import element
@freeze
class Ctb(Detector): class Ctb(Detector):
def __init__(self, id = 0): def __init__(self, id = 0):
super().__init__(id) super().__init__(id)
self._frozen = False self._frozen = False
self._dacs = CtbDacs(self) # self._dacs = CtbDacs(self)
self._dacs = NamedDacs(self)
@property @property
def dacs(self): def dacs(self):

View File

@ -36,6 +36,79 @@ class Dac(DetectorProperty):
dacstr = ''.join([f'{item:5d}' for item in self.get()]) dacstr = ''.join([f'{item:5d}' for item in self.get()])
return f'{self.__name__:15s}:{dacstr}' 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: class DetectorDacs:
_dacs = [] _dacs = []
@ -50,7 +123,7 @@ class DetectorDacs:
# Index to support iteration # Index to support iteration
self._current = 0 self._current = 0
# Populate the dacs # Name the attributes?
for _d in self._dacs: for _d in self._dacs:
setattr(self, '_'+_d[0], Dac(*_d, detector)) setattr(self, '_'+_d[0], Dac(*_d, detector))
@ -59,6 +132,9 @@ class DetectorDacs:
def __getattr__(self, name): def __getattr__(self, name):
return self.__getattribute__('_' + name) return self.__getattribute__('_' + name)
@property
def dacnames(self):
return [_d[0] for _d in _dacs]
def __setattr__(self, name, value): def __setattr__(self, name, value):
if name in self._dacnames: if name in self._dacnames:

View File

@ -1571,8 +1571,16 @@ class Detector(CppDetectorApi):
@property @property
def daclist(self): def daclist(self):
"""Gets the list of enums for every dac for this detector.""" """
return self.getDacList() List of enums for every dac for this detector.
:setter: Only implemented for Chiptestboard
"""
return self.getDacNames()
@daclist.setter
def daclist(self, value):
self.setDacNames(value)
@property @property
def dacvalues(self): def dacvalues(self):

View File

@ -1427,6 +1427,19 @@ void init_det(py::module &m) {
(void (Detector::*)(bool, sls::Positions)) & (void (Detector::*)(bool, sls::Positions)) &
Detector::setLEDEnable, Detector::setLEDEnable,
py::arg(), py::arg() = Positions{}) py::arg(), py::arg() = Positions{})
.def("setDacNames",
(void (Detector::*)(const std::vector<std::string>)) &
Detector::setDacNames,
py::arg())
.def("getDacNames", (std::vector<std::string>(Detector::*)() const) &
Detector::getDacNames)
.def("getDacIndex",
(defs::dacIndex(Detector::*)(const std::string &)) &
Detector::getDacIndex,
py::arg())
.def("getDacName",
(std::string(Detector::*)(defs::dacIndex)) & Detector::getDacName,
py::arg())
.def("setPattern", .def("setPattern",
(void (Detector::*)(const std::string &, sls::Positions)) & (void (Detector::*)(const std::string &, sls::Positions)) &
Detector::setPattern, Detector::setPattern,

View File

@ -7,6 +7,7 @@ set(SOURCES
src/CmdProxy.cpp src/CmdProxy.cpp
src/CmdParser.cpp src/CmdParser.cpp
src/Pattern.cpp src/Pattern.cpp
src/CtbConfig.cpp
) )
add_library(slsDetectorObject OBJECT add_library(slsDetectorObject OBJECT

View File

@ -1613,6 +1613,14 @@ class Detector {
/** [CTB] Default is enabled. */ /** [CTB] Default is enabled. */
void setLEDEnable(bool enable, Positions pos = {}); void setLEDEnable(bool enable, Positions pos = {});
void setDacNames(const std::vector<std::string> names);
std::vector<std::string> getDacNames() const;
defs::dacIndex getDacIndex(const std::string& name);
std::string getDacName(defs::dacIndex i);
///@} ///@}
/** @name Pattern */ /** @name Pattern */

View File

@ -1056,11 +1056,10 @@ std::string CmdProxy::TemperatureValues(int action) {
std::string CmdProxy::Dac(int action) { std::string CmdProxy::Dac(int action) {
std::ostringstream os; std::ostringstream os;
os << cmd << ' '; os << cmd << ' ';
auto type = det->getDetectorType().squash();
// dac indices only for ctb // dac indices only for ctb
if (args.size() > 0 && action != defs::HELP_ACTION) { if (args.size() > 0 && action != defs::HELP_ACTION) {
if (is_int(args[0]) && if (is_int(args[0]) && type != defs::CHIPTESTBOARD) {
det->getDetectorType().squash() != defs::CHIPTESTBOARD) {
throw sls::RuntimeError( throw sls::RuntimeError(
"Dac indices can only be used for chip test board. Use daclist " "Dac indices can only be used for chip test board. Use daclist "
"to get list of dac names for current detector."); "to get list of dac names for current detector.");
@ -1077,7 +1076,14 @@ std::string CmdProxy::Dac(int action) {
if (args.empty()) if (args.empty())
WrongNumberOfParameters(1); // This prints slightly wrong WrongNumberOfParameters(1); // This prints slightly wrong
defs::dacIndex dacIndex = StringTo<defs::dacIndex>(args[0]); defs::dacIndex dacIndex{};
//TODO! Remove if
if (type == defs::CHIPTESTBOARD && !is_int(args[0])) {
dacIndex = det->getDacIndex(args[0]);
} else {
dacIndex = StringTo<defs::dacIndex>(args[0]);
}
bool mV = false; bool mV = false;
if (args.size() == 2) { if (args.size() == 2) {
@ -1095,7 +1101,11 @@ std::string CmdProxy::Dac(int action) {
if (args.empty()) if (args.empty())
WrongNumberOfParameters(1); // This prints slightly wrong WrongNumberOfParameters(1); // This prints slightly wrong
defs::dacIndex dacIndex = StringTo<defs::dacIndex>(args[0]); defs::dacIndex dacIndex{};
if (type == defs::CHIPTESTBOARD && !is_int(args[0]))
dacIndex = det->getDacIndex(args[0]);
else
dacIndex = StringTo<defs::dacIndex>(args[0]);
bool mV = false; bool mV = false;
if (args.size() == 3) { if (args.size() == 3) {
if ((args[2] != "mv") && (args[2] != "mV")) { if ((args[2] != "mv") && (args[2] != "mV")) {
@ -1115,6 +1125,38 @@ std::string CmdProxy::Dac(int action) {
return os.str(); return os.str();
} }
std::string CmdProxy::DacList(const int action) {
std::ostringstream os;
os << cmd << ' ';
if (action == slsDetectorDefs::HELP_ACTION) {
os << "\n\t[dacname1 dacname2 .. dacname18] \n\t\t[ChipTestBoard] Set "
"the list of dac names for this detector.\n\t\t[All] Gets the "
"list "
"of "
"dac names for every dac for this detector."
<< '\n';
} else if (action == slsDetectorDefs::GET_ACTION) {
if (!args.empty()) {
WrongNumberOfParameters(0);
}
auto t = det->getDacNames();
os << sls::ToString(t) << '\n';
} else if (action == slsDetectorDefs::PUT_ACTION) {
if (det->getDetectorType().squash() != defs::CHIPTESTBOARD) {
throw sls::RuntimeError("This detector already has fixed dac "
"names. Cannot change them.");
}
if (args.size() != 18) {
WrongNumberOfParameters(18);
}
det->setDacNames(args);
os << ToString(args) << '\n';
} else {
throw sls::RuntimeError("Unknown action");
}
return os.str();
}
std::string CmdProxy::DacValues(int action) { std::string CmdProxy::DacValues(int action) {
std::ostringstream os; std::ostringstream os;
os << cmd << ' '; os << cmd << ' ';
@ -1134,13 +1176,15 @@ std::string CmdProxy::DacValues(int action) {
WrongNumberOfParameters(1); WrongNumberOfParameters(1);
} }
auto t = det->getDacList(); auto t = det->getDacList();
auto names = det->getDacNames();
auto name_it = names.begin();
os << '['; os << '[';
auto it = t.cbegin(); auto it = t.cbegin();
os << ToString(*it) << ' '; os << ToString(*name_it++) << ' ';
os << OutString(det->getDAC(*it++, mv, std::vector<int>{det_id})) os << OutString(det->getDAC(*it++, mv, std::vector<int>{det_id}))
<< (!args.empty() ? " mV" : ""); << (!args.empty() ? " mV" : "");
while (it != t.cend()) { while (it != t.cend()) {
os << ", " << ToString(*it) << ' '; os << ", " << ToString(*name_it++) << ' ';
os << OutString(det->getDAC(*it++, mv, std::vector<int>{det_id})) os << OutString(det->getDAC(*it++, mv, std::vector<int>{det_id}))
<< (!args.empty() ? " mV" : ""); << (!args.empty() ? " mV" : "");
} }

View File

@ -837,7 +837,7 @@ class CmdProxy {
/* dacs */ /* dacs */
{"dac", &CmdProxy::Dac}, {"dac", &CmdProxy::Dac},
{"daclist", &CmdProxy::daclist}, {"daclist", &CmdProxy::DacList},
{"dacvalues", &CmdProxy::DacValues}, {"dacvalues", &CmdProxy::DacValues},
{"resetdacs", &CmdProxy::ResetDacs}, {"resetdacs", &CmdProxy::ResetDacs},
{"defaultdac", &CmdProxy::DefaultDac}, {"defaultdac", &CmdProxy::DefaultDac},
@ -1124,6 +1124,7 @@ class CmdProxy {
std::string TemperatureValues(int action); std::string TemperatureValues(int action);
/* dacs */ /* dacs */
std::string Dac(int action); std::string Dac(int action);
std::string DacList(int action);
std::string DacValues(int action); std::string DacValues(int action);
std::string ResetDacs(int action); std::string ResetDacs(int action);
std::string DefaultDac(int action); std::string DefaultDac(int action);
@ -1465,10 +1466,6 @@ class CmdProxy {
/* dacs */ /* dacs */
GET_COMMAND_NOID(
daclist, getDacList,
"\n\tGets the list of commands for every dac for this detector.");
/* on chip dacs */ /* on chip dacs */
INTEGER_USER_IND_COMMAND( INTEGER_USER_IND_COMMAND(
vchip_comp_fe, getOnChipDAC, setOnChipDAC, StringTo<int>, vchip_comp_fe, getOnChipDAC, setOnChipDAC, StringTo<int>,

View File

@ -0,0 +1,72 @@
#include "CtbConfig.h"
#include "SharedMemory.h"
#include "sls/ToString.h"
#include "sls/string_utils.h"
#include <algorithm>
#include <fstream>
#include <sstream>
namespace sls {
CtbConfig::CtbConfig(){
for (size_t i=0; i!=num_dacs; ++i){
setDacName(i, "dac"+ToString(i));
}
}
void CtbConfig::check_index(size_t i) const {
if (!(i < num_dacs)) {
std::ostringstream oss;
oss << "DAC index is too large needs to be below " << num_dacs;
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");
// dacname_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_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<std::string>& names){
for (size_t i = 0; i!=num_dacs; ++i){
setDacName(i, names[i]);
}
}
std::string CtbConfig::getDacName(size_t index) const {
return dacnames + index * name_length;
}
std::vector<std::string> CtbConfig::getDacNames() const {
std::vector<std::string> names;
for (size_t i = 0; i != num_dacs; ++i)
names.push_back(getDacName(i));
return names;
}
const char* CtbConfig::shm_tag(){
return shm_tag_;
}
} // namespace sls

View File

@ -0,0 +1,31 @@
#pragma once
#include <string>
#include <vector>
namespace sls {
class CtbConfig {
static constexpr size_t name_length = 20;
static constexpr size_t num_dacs = 18;
static constexpr const char* shm_tag_ = "ctbdacs";
char dacnames[name_length * num_dacs]{};
void check_index(size_t i) const;
void check_size(const std::string &name) const;
public:
CtbConfig();
CtbConfig(const CtbConfig&) = default;
CtbConfig(CtbConfig&&) = default;
CtbConfig& operator=(const CtbConfig&) = default;
~CtbConfig() = default;
void setDacNames(const std::vector<std::string> &names);
void setDacName(size_t index, const std::string &name);
std::string getDacName(size_t index) const;
std::vector<std::string> getDacNames() const;
static const char* shm_tag();
};
} // namespace sls

View File

@ -7,6 +7,7 @@
#include "CmdProxy.h" #include "CmdProxy.h"
#include "DetectorImpl.h" #include "DetectorImpl.h"
#include "Module.h" #include "Module.h"
#include "CtbConfig.h"
#include "sls/Pattern.h" #include "sls/Pattern.h"
#include "sls/container_utils.h" #include "sls/container_utils.h"
#include "sls/file_utils.h" #include "sls/file_utils.h"
@ -21,6 +22,7 @@
namespace sls { namespace sls {
void freeSharedMemory(int detectorIndex, int moduleIndex) { void freeSharedMemory(int detectorIndex, int moduleIndex) {
// single module // single module
if (moduleIndex >= 0) { if (moduleIndex >= 0) {
SharedMemory<sharedModule> moduleShm(detectorIndex, moduleIndex); SharedMemory<sharedModule> moduleShm(detectorIndex, moduleIndex);
@ -44,6 +46,11 @@ void freeSharedMemory(int detectorIndex, int moduleIndex) {
SharedMemory<sharedModule> moduleShm(detectorIndex, i); SharedMemory<sharedModule> moduleShm(detectorIndex, i);
moduleShm.RemoveSharedMemory(); moduleShm.RemoveSharedMemory();
} }
// Ctb configuration
SharedMemory<CtbConfig> ctbShm(detectorIndex, -1, CtbConfig::shm_tag());
if (ctbShm.IsExisting())
ctbShm.RemoveSharedMemory();
} }
using defs = slsDetectorDefs; using defs = slsDetectorDefs;
@ -2067,6 +2074,42 @@ void Detector::setLEDEnable(bool enable, Positions pos) {
pimpl->Parallel(&Module::setLEDEnable, pos, enable); pimpl->Parallel(&Module::setLEDEnable, pos, enable);
} }
void Detector::setDacNames(const std::vector<std::string> names) {
if (getDetectorType().squash() != defs::CHIPTESTBOARD)
throw RuntimeError("Named dacs only for CTB");
pimpl->setCtbDacNames(names);
}
std::vector<std::string> Detector::getDacNames() const {
std::vector<std::string> names;
auto type = getDetectorType().squash();
if (type == defs::CHIPTESTBOARD)
return pimpl->getCtbDacNames();
for (const auto &index : getDacList())
names.push_back(ToString(index));
return names;
}
defs::dacIndex Detector::getDacIndex(const std::string &name) {
auto type = getDetectorType().squash();
if (type == defs::CHIPTESTBOARD) {
auto names = getDacNames();
auto it = std::find(names.begin(), names.end(), name);
if (it == names.end())
throw RuntimeError("Dacname not found");
return static_cast<defs::dacIndex>(it - names.begin());
}
return StringTo<defs::dacIndex>(name);
}
std::string Detector::getDacName(defs::dacIndex i) {
auto type = getDetectorType().squash();
if (type == defs::CHIPTESTBOARD)
return pimpl->getCtbDacName(i);
return ToString(i);
}
// Pattern // Pattern
void Detector::setPattern(const std::string &fname, Positions pos) { void Detector::setPattern(const std::string &fname, Positions pos) {

View File

@ -32,7 +32,8 @@
namespace sls { namespace sls {
DetectorImpl::DetectorImpl(int detector_index, bool verify, bool update) DetectorImpl::DetectorImpl(int detector_index, bool verify, bool update)
: detectorIndex(detector_index), shm(detector_index, -1) { : detectorIndex(detector_index), shm(detector_index, -1),
ctb_shm(detector_index, -1, CtbConfig::shm_tag()) {
setupDetector(verify, update); setupDetector(verify, update);
} }
@ -44,6 +45,9 @@ void DetectorImpl::setupDetector(bool verify, bool update) {
if (update) { if (update) {
updateUserdetails(); updateUserdetails();
} }
if (ctb_shm.IsExisting())
ctb_shm.OpenSharedMemory();
} }
void DetectorImpl::setAcquiringFlag(bool flag) { shm()->acquiringFlag = flag; } void DetectorImpl::setAcquiringFlag(bool flag) { shm()->acquiringFlag = flag; }
@ -74,6 +78,10 @@ void DetectorImpl::freeSharedMemory(int detectorIndex, int detPos) {
SharedMemory<sharedModule> moduleShm(detectorIndex, i); SharedMemory<sharedModule> moduleShm(detectorIndex, i);
moduleShm.RemoveSharedMemory(); moduleShm.RemoveSharedMemory();
} }
SharedMemory<CtbConfig> ctbShm(detectorIndex, -1, CtbConfig::shm_tag());
if (ctbShm.IsExisting())
ctbShm.RemoveSharedMemory();
} }
void DetectorImpl::freeSharedMemory() { void DetectorImpl::freeSharedMemory() {
@ -86,6 +94,9 @@ void DetectorImpl::freeSharedMemory() {
// clear detector shm // clear detector shm
shm.RemoveSharedMemory(); shm.RemoveSharedMemory();
client_downstream = false; client_downstream = false;
if (ctb_shm.IsExisting())
ctb_shm.RemoveSharedMemory();
} }
std::string DetectorImpl::getUserDetails() { std::string DetectorImpl::getUserDetails() {
@ -144,6 +155,8 @@ void DetectorImpl::initSharedMemory(bool verify) {
throw SharedMemoryError("Shared memory version mismatch!"); throw SharedMemoryError("Shared memory version mismatch!");
} }
} }
// std::cout <<
} }
void DetectorImpl::initializeDetectorStructure() { void DetectorImpl::initializeDetectorStructure() {
@ -245,6 +258,16 @@ void DetectorImpl::setHostname(const std::vector<std::string> &name) {
addModule(hostname); addModule(hostname);
} }
updateDetectorSize(); updateDetectorSize();
// Here we know the detector type and can add ctb shared memory
// if needed, CTB dac names are only on detector level
if (shm()->detType == defs::CHIPTESTBOARD) {
if (ctb_shm.IsExisting())
ctb_shm.OpenSharedMemory();
else
ctb_shm.CreateSharedMemory();
}
} }
void DetectorImpl::addModule(const std::string &hostname) { void DetectorImpl::addModule(const std::string &hostname) {
@ -1379,4 +1402,16 @@ void DetectorImpl::setDefaultDac(defs::dacIndex index, int defaultValue,
Parallel(&Module::setDefaultDac, pos, index, defaultValue, sett); Parallel(&Module::setDefaultDac, pos, index, defaultValue, sett);
} }
std::vector<std::string> DetectorImpl::getCtbDacNames() const {
return ctb_shm()->getDacNames();
}
void DetectorImpl::setCtbDacNames(const std::vector<std::string> &names) {
ctb_shm()->setDacNames(names);
}
std::string DetectorImpl::getCtbDacName(defs::dacIndex i) const {
return ctb_shm()->getDacName(static_cast<int>(i));
}
} // namespace sls } // namespace sls

View File

@ -7,6 +7,8 @@
#include "sls/logger.h" #include "sls/logger.h"
#include "sls/sls_detector_defs.h" #include "sls/sls_detector_defs.h"
#include "CtbConfig.h"
class ZmqSocket; class ZmqSocket;
class detectorData; class detectorData;
@ -298,6 +300,11 @@ class DetectorImpl : public virtual slsDetectorDefs {
void setDefaultDac(defs::dacIndex index, int defaultValue, void setDefaultDac(defs::dacIndex index, int defaultValue,
defs::detectorSettings sett, Positions pos); defs::detectorSettings sett, Positions pos);
std::vector<std::string> getCtbDacNames() const;
std::string getCtbDacName(defs::dacIndex i) const;
void setCtbDacNames(const std::vector<std::string>& names);
private: private:
/** /**
* Creates/open shared memory, initializes detector structure and members * Creates/open shared memory, initializes detector structure and members
@ -381,6 +388,7 @@ class DetectorImpl : public virtual slsDetectorDefs {
const int detectorIndex{0}; const int detectorIndex{0};
sls::SharedMemory<sharedDetector> shm{0, -1}; sls::SharedMemory<sharedDetector> shm{0, -1};
sls::SharedMemory<CtbConfig> ctb_shm{0, -1, "a"};
std::vector<std::unique_ptr<sls::Module>> modules; std::vector<std::unique_ptr<sls::Module>> modules;
/** data streaming (down stream) enabled in client (zmq sckets created) */ /** data streaming (down stream) enabled in client (zmq sckets created) */

View File

@ -19,7 +19,6 @@
#include <fcntl.h> // O_CREAT, O_TRUNC.. #include <fcntl.h> // O_CREAT, O_TRUNC..
#include <iostream> #include <iostream>
#include <sstream> #include <sstream>
// #include <stdio.h> // printf
#include <sys/mman.h> // shared memory #include <sys/mman.h> // shared memory
#include <sys/stat.h> // fstat #include <sys/stat.h> // fstat
#include <unistd.h> #include <unistd.h>
@ -36,11 +35,9 @@ namespace sls {
template <typename T> class SharedMemory { template <typename T> class SharedMemory {
public: public:
/** //moduleid of -1 creates a detector only shared memory
* moduleid of -1 creates a detector only shared memory SharedMemory(int detectorId, int moduleIndex, const std::string& tag = "") {
*/ name = ConstructSharedMemoryName(detectorId, moduleIndex, tag);
SharedMemory(int detectorId, int moduleIndex) {
name = ConstructSharedMemoryName(detectorId, moduleIndex);
} }
/** /**
@ -103,11 +100,7 @@ template <typename T> class SharedMemory {
return ret; return ret;
} }
/**
* Get shared memory name
*/
std::string GetName() const { return name; } std::string GetName() const { return name; }
size_t size() const { return shmSize; } size_t size() const { return shmSize; }
/** /**
@ -133,8 +126,10 @@ template <typename T> class SharedMemory {
RemoveSharedMemory(); RemoveSharedMemory();
throw SharedMemoryError(msg); throw SharedMemoryError(msg);
} }
// int *pInt = new (buf) int(3);
shared_struct = MapSharedMemory(); shared_struct = MapSharedMemory();
new (shared_struct) T{}; // is this ok?
LOG(logINFO) << "Shared memory created " << name; LOG(logINFO) << "Shared memory created " << name;
} }
@ -211,7 +206,7 @@ template <typename T> class SharedMemory {
* @param moduleIndex module id, -1 if a detector shared memory * @param moduleIndex module id, -1 if a detector shared memory
* @returns shared memory name * @returns shared memory name
*/ */
std::string ConstructSharedMemoryName(int detectorId, int moduleIndex) { std::string ConstructSharedMemoryName(int detectorId, int moduleIndex, const std::string& tag) {
// using environment path // using environment path
std::string sEnvPath; std::string sEnvPath;
@ -222,8 +217,12 @@ template <typename T> class SharedMemory {
} }
std::stringstream ss; std::stringstream ss;
if (moduleIndex < 0) if (moduleIndex < 0){
ss << SHM_DETECTOR_PREFIX << detectorId << sEnvPath; ss << SHM_DETECTOR_PREFIX << detectorId << sEnvPath;
if (!tag.empty())
ss << "_" << tag;
}
else else
ss << SHM_DETECTOR_PREFIX << detectorId << SHM_MODULE_PREFIX ss << SHM_DETECTOR_PREFIX << detectorId << SHM_MODULE_PREFIX
<< moduleIndex << sEnvPath; << moduleIndex << sEnvPath;
@ -293,15 +292,10 @@ template <typename T> class SharedMemory {
return 0; return 0;
} }
/** Shared memory name */
std::string name; std::string name;
/** File descriptor */
int fd{-1}; int fd{-1};
/** shm size */
size_t shmSize{0}; size_t shmSize{0};
T *shared_struct{nullptr}; T *shared_struct{nullptr};
}; };

View File

@ -18,6 +18,7 @@ target_sources(tests PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/test-CmdParser.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test-CmdParser.cpp
${CMAKE_CURRENT_SOURCE_DIR}/test-Module.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test-Module.cpp
${CMAKE_CURRENT_SOURCE_DIR}/test-Pattern.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test-Pattern.cpp
${CMAKE_CURRENT_SOURCE_DIR}/test-CtbConfig.cpp
) )
target_include_directories(tests PUBLIC "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/../src>") target_include_directories(tests PUBLIC "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/../src>")

View File

@ -590,13 +590,13 @@ TEST_CASE("master", "[.cmd]") {
} }
{ {
std::ostringstream oss1; std::ostringstream oss1;
proxy.Call("master", {"0"}, 0, PUT, oss3); proxy.Call("master", {"0"}, 0, PUT, oss1);
REQUIRE(oss3.str() == "master 0\n"); REQUIRE(oss1.str() == "master 0\n");
} }
{ {
std::ostringstream oss1; std::ostringstream oss1;
proxy.Call("master", {"1"}, 0, PUT, oss3); proxy.Call("master", {"1"}, 0, PUT, oss1);
REQUIRE(oss3.str() == "master 1\n"); REQUIRE(oss1.str() == "master 1\n");
} }
REQUIRE_THROWS(proxy.Call("master", {"1"}, -1, PUT)); REQUIRE_THROWS(proxy.Call("master", {"1"}, -1, PUT));
// set all to slaves, and then master // set all to slaves, and then master

View File

@ -0,0 +1,59 @@
#include "catch.hpp"
#include <string>
#include <stdlib.h>
#include "SharedMemory.h"
#include "CtbConfig.h"
using namespace sls;
#include <fstream>
TEST_CASE("Default construction"){
static_assert(sizeof(CtbConfig) == 360); // 18*20
CtbConfig c;
auto names = c.getDacNames();
REQUIRE(names.size() == 18);
REQUIRE(names[0] == "dac0");
REQUIRE(names[1] == "dac1");
REQUIRE(names[2] == "dac2");
REQUIRE(names[3] == "dac3");
}
TEST_CASE("Set and get a single dac name"){
CtbConfig c;
c.setDacName(3, "vrf");
auto names = c.getDacNames();
REQUIRE(c.getDacName(3) == "vrf");
REQUIRE(names[3] == "vrf");
}
TEST_CASE("Set a name that is too large throws"){
CtbConfig c;
REQUIRE_THROWS(c.setDacName(3, "somestringthatisreallytolongforadatac"));
}
TEST_CASE("Length of dac name cannot be 0"){
CtbConfig c;
REQUIRE_THROWS(c.setDacName(1, ""));
}
TEST_CASE("Copy a CTB config"){
CtbConfig c1;
c1.setDacName(5, "somename");
auto c2 = c1;
//change the name on the first object
//to detecto shallow copy
c1.setDacName(5, "someothername");
REQUIRE(c2.getDacName(5) == "somename");
}
TEST_CASE("Move CtbConfig "){
CtbConfig c1;
c1.setDacName(3, "yetanothername");
CtbConfig c2(std::move(c1));
REQUIRE(c2.getDacName(3) == "yetanothername");
}

View File

@ -134,3 +134,31 @@ TEST_CASE("Create several shared memories", "[detector]") {
CHECK(v[i].IsExisting() == false); CHECK(v[i].IsExisting() == false);
} }
} }
TEST_CASE("Create create a shared memory with a tag"){
SharedMemory<int> shm(0, -1, "ctbdacs");
REQUIRE(shm.GetName() == "/slsDetectorPackage_detector_0_ctbdacs");
}
TEST_CASE("Create create a shared memory with a tag when SLSDETNAME is set"){
// 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);
setenv(SHM_ENV_NAME, "myprefix", 1);
SharedMemory<int> shm(0, -1, "ctbdacs");
REQUIRE(shm.GetName() == "/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);
}