15 : hasParsed(false), _lmapFileName(
std::move(lmapFileName)) {
38 for(
auto& p : reg.plugins) {
39 auto thisp = boost::static_pointer_cast<const LogicalNameMappingBackend>(shared_from_this());
40 p->postParsingHook(thisp);
68 plug->openHook(boost::dynamic_pointer_cast<LogicalNameMappingBackend>(shared_from_this()));
76 auto& variable = nameAndVar.second;
77 if(variable.isConstant) {
78 std::lock_guard<std::mutex> lk(variable.valueTable_mutex);
80 boost::fusion::at_key<decltype(v)>(variable.valueTable.table).latestVersion = versionForConstants;
102 if(
device.second->isOpen()) {
116 std::string , std::map<std::string, std::string> parameters) {
118 if(parameters[
"map"].empty()) {
121 auto ptr = boost::make_shared<LogicalNameMappingBackend>(parameters[
"map"]);
122 parameters.erase(parameters.find(
"map"));
123 ptr->_parameters = parameters;
124 return boost::static_pointer_cast<DeviceBackend>(ptr);
129 template<
typename UserType>
132 size_t omitPlugins) {
135 boost::shared_ptr<NDRegisterAccessor<UserType>> returnValue;
137 if(info.plugins.size() <= omitPlugins) {
140 getRegisterAccessor_internal<UserType>(registerPathName, numberOfWords, wordOffsetInRegister, flags);
143 returnValue = info.plugins[omitPlugins]->getAccessor<UserType>(
144 boost::static_pointer_cast<LogicalNameMappingBackend>(shared_from_this()), numberOfWords,
145 wordOffsetInRegister, flags, omitPlugins);
148 returnValue->setExceptionBackend(shared_from_this());
155 template<
typename UserType>
163 if(info.length != 0) {
165 if(numberOfWords == 0) {
166 numberOfWords = info.length;
168 if((numberOfWords + wordOffsetInRegister) > info.length) {
171 "LogicalNameMappingBackend: Error creating accessor. Number of words plus offset too large in ") +
177 size_t actualOffset = size_t(info.firstIndex) + wordOffsetInRegister;
178 size_t actualLength = (numberOfWords > 0 ? numberOfWords : size_t(info.length));
181 boost::shared_ptr<NDRegisterAccessor<UserType>> ptr;
184 std::string devName = info.deviceName;
185 if(devName !=
"this") {
186 _targetDevice =
_devices[info.deviceName].get();
189 _targetDevice =
this;
192 if(_targetDevice ==
nullptr) {
194 "exception thrown in open()!");
198 RegisterPath(info.registerName), actualLength, actualOffset, flags);
202 shared_from_this(), registerPathName, actualLength, actualOffset, flags));
205 ptr = boost::shared_ptr<NDRegisterAccessor<UserType>>(
211 shared_from_this(), registerPathName, actualLength, actualOffset, flags));
215 "For this register type, a RegisterAccessor cannot be obtained (name of logical register: " +
216 registerPathName +
").");
231 std::map<std::string, RegisterCatalogue> catalogueMap;
238 auto targetType = lnmInfo.targetType;
245 std::string devName = lnmInfo.deviceName;
249 if(devName !=
"this") {
250 const auto& cat = catalogueMap.at(devName);
251 if(!cat.hasRegister(lnmInfo.registerName)) {
254 target_info = cat.getRegister(lnmInfo.registerName);
261 for(
auto& plugin : i.plugins) {
279 lnmInfo.writeable =
false;
285 if(lnmInfo.length == 0) {
289 lnmInfo.tags = target_info.
getTags();
290 lnmInfo.engineeringUnit = target_info.
getUnit();
298 for(
auto& plugin : lnmInfo.plugins) {
310 template<
typename UserType>
315 void getRegisterAccessor_impl(
const RegisterPath& registerPathName,
size_t numberOfWords,
316 size_t wordOffsetInRegister,
AccessModeFlags flags,
size_t omitPlugins) {
318 registerPathName, numberOfWords, wordOffsetInRegister, std::move(flags), omitPlugins);
322 void getRegisterAccessor_internal(
const RegisterPath& registerPathName,
size_t numberOfWords,
325 registerPathName, numberOfWords, wordOffsetInRegister, std::move(flags));
335 d.second->setException(message);
345 auto& lnmVariable = _variables[info.name];
346 auto& vtEntry = boost::fusion::at_key<decltype(arg)>(lnmVariable.valueTable.table);
347 for(auto& sub : vtEntry.subscriptions) {
349 throw ChimeraTK::runtime_error(message);
352 sub.second.push_overwrite_exception(std::current_exception());
361 _asyncReadActive =
false;
364 for(
auto& reg : _catalogue_mutable) {
366 plug->exceptionHook();
373 void LogicalNameMappingBackend::activateAsyncRead() noexcept {
374 if(!isFunctional()) {
381 auto asyncWasActive = _asyncReadActive.exchange(
true);
387 for(
auto& d : _devices) {
388 d.second->activateAsyncRead();
393 for(
auto& r : _catalogue_mutable) {
395 if(info.targetType == LNMBackendRegisterInfo::TargetType::VARIABLE) {
396 auto& lnmVariable = _variables[info.name];
399 auto& vtEntry = boost::fusion::at_key<decltype(arg)>(lnmVariable.valueTable.table);
401 if(vtEntry.latestVersion < v) {
402 vtEntry.latestVersion = v;
404 for(
auto& sub : vtEntry.subscriptions) {
406 sub.second.push_overwrite({vtEntry.latestValue, vtEntry.latestValidity, vtEntry.latestVersion});
408 catch(std::system_error& e) {
409 std::cerr <<
"Caught system error in activateAsyncRead(): " << e.what() << std::endl;
415 catch(std::bad_cast& e) {
427 std::unordered_set<std::string> LogicalNameMappingBackend::getTargetDevices()
const {
428 std::unordered_set<std::string> ret;
429 for(
const auto& info : _catalogue_mutable) {
430 if(info.deviceName !=
"this" && !info.deviceName.empty()) {
431 ret.insert(info.deviceName);
439 std::set<DeviceBackend::BackendID> LogicalNameMappingBackend::getInvolvedBackendIDs() {
441 std::set<DeviceBackend::BackendID> retVal{getBackendID()};
442 for(
auto& devIter : _devices) {
443 auto& dev = devIter.second;
444 retVal.merge(dev->getInvolvedBackendIDs());
#define INSTANTIATE_TEMPLATE_FOR_CHIMERATK_USER_TYPES(TemplateClass)
#define FILL_VIRTUAL_FUNCTION_TEMPLATE_VTABLE(functionName)
Fill the vtable of a virtual function template defined with DEFINE_VIRTUAL_FUNCTION_TEMPLATE.
Set of AccessMode flags with additional functionality for an easier handling.
static BackendFactory & getInstance()
Static function to get an instance of factory.
boost::shared_ptr< DeviceBackend > createBackend(const std::string &aliasOrUri)
Create a new backend and return the instance as a shared pointer.
Class describing the actual payload data format of a register in an abstract manner.
The base class for backends providing IO functionality for the Device class.
boost::shared_ptr< NDRegisterAccessor< UserType > > getRegisterAccessor(const RegisterPath ®isterPathName, size_t numberOfWords, size_t wordOffsetInRegister, AccessModeFlags flags)
Get a NDRegisterAccessor object from the register name.
bool isFunctional() const noexcept final
Return whether a device is working as intended, usually this means it is opened and does not have any...
void setOpenedAndClearException() noexcept
Backends should call this function at the end of a (successful) open() call.
std::string getActiveExceptionMessage() noexcept
std::atomic< bool > _opened
flag if backend is opened
void close()
Close the device.
RegisterCatalogue getRegisterCatalogue() const
Return the register catalogue with detailed information on all registers.
void open(std::string const &aliasName)
Open a device by the given alias name from the DMAP file.
RegisterInfo structure for the LogicalNameMappingBackend.
Logical name map: store information from xlmap file and provide it to the LogicalNameMappingBackend a...
BackendRegisterCatalogue< LNMBackendRegisterInfo > parseFile(const std::string &fileName)
parse the given XML file
Backend to map logical register names onto real hardware registers.
BackendRegisterCatalogue< LNMBackendRegisterInfo > _catalogue_mutable
We need to make the catalogue mutable, since we fill it within getRegisterCatalogue()
std::unordered_set< std::string > getTargetDevices() const
Obtain list of all target devices referenced in the catalogue.
bool hasParsed
flag if already parsed
static boost::shared_ptr< DeviceBackend > createInstance(std::string address, std::map< std::string, std::string > parameters)
void parse() const
parse the logical map file, if not yet done
RegisterCatalogue getRegisterCatalogue() const override
Return the register catalogue with detailed information on all registers.
std::map< std::string, boost::shared_ptr< DeviceBackend > > _devices
map of target devices
LogicalNameMappingBackend(std::string lmapFileName="")
std::atomic< bool > _asyncReadActive
Flag storing whether asynchronous read has been activated.
boost::shared_ptr< NDRegisterAccessor< UserType > > getRegisterAccessor_internal(const RegisterPath ®isterPathName, size_t numberOfWords, size_t wordOffsetInRegister, AccessModeFlags flags)
void close() override
Close the device.
boost::shared_ptr< NDRegisterAccessor< UserType > > getRegisterAccessor_impl(const RegisterPath ®isterPathName, size_t numberOfWords, size_t wordOffsetInRegister, AccessModeFlags flags, size_t omitPlugins=0)
void setExceptionImpl() noexcept override
Function to be (optionally) implemented by backends if additional actions are needed when switching t...
void open() override
Open the device.
std::map< std::string, LNMVariable > _variables
Map of variables and constants.
bool catalogueCompleted
Flag whether the catalogue has already been filled with extra information from the target backends.
std::map< std::string, std::string > _parameters
map of parameters passed through the CDD
std::string _lmapFileName
name of the logical map file
Catalogue of register information.
std::string getDescription() const
Return the description of the register.
bool isWriteable() const
Return whether the register is writeable.
BackendRegisterInfoBase & getImpl()
Return a reference to the implementation object.
unsigned int getNumberOfChannels() const
Return number of channels in register.
const DataDescriptor & getDataDescriptor() const
Return desciption of the actual payload data for this register.
std::set< std::string > getTags() const
Get the list of tags that are associated with this register.
AccessModeFlags getSupportedAccessModes() const
Return all supported AccessModes for this register.
unsigned int getNumberOfElements() const
Return number of elements per channel.
bool isReadable() const
Return whether the register is readable.
std::string getUnit() const
Return the engineering unit of the register.
Class to store a register path name.
Class for generating and holding version numbers without exposing a numeric representation.
Exception thrown when a logic error has occured.
void callForType(const std::type_info &type, LAMBDATYPE lambda)
Helper function for running code which uses some compile-time type that is specified at runtime as a ...
@ raw
Raw access: disable any possible conversion from the original hardware data type into the given UserT...