-
Martin Christoph Hierholzer authored
- ControlSystemModule - VirtualModule - findTag - excludeTag and some related functions.
Martin Christoph Hierholzer authored- ControlSystemModule - VirtualModule - findTag - excludeTag and some related functions.
Module.cc 8.94 KiB
// SPDX-FileCopyrightText: Deutsches Elektronen-Synchrotron DESY, MSK, ChimeraTK Project <chimeratk-support@desy.de>
// SPDX-License-Identifier: LGPL-3.0-or-later
#include "Module.h"
#include "Application.h"
#include "ApplicationModule.h"
#include "ConfigReader.h"
#include "DeviceModule.h"
namespace ChimeraTK {
Module::Module(EntityOwner* owner, const std::string& name, const std::string& description,
const std::unordered_set<std::string>& tags)
: EntityOwner(name, description, tags), _owner(owner) {
if(_owner != nullptr) _owner->registerModule(this);
}
/*********************************************************************************************************************/
Module::~Module() {
if(_owner != nullptr) _owner->unregisterModule(this);
}
/*********************************************************************************************************************/
Module& Module::operator=(Module&& other) {
EntityOwner::operator=(std::move(other));
_owner = other._owner;
if(_owner != nullptr) _owner->registerModule(this, false);
// note: the other module unregisters itself in its destructor - which will be called next after any move operation
return *this;
}
/*********************************************************************************************************************/
void Module::run() {
testableModeReached = true; // Modules which don't implement run() have now reached testable mode
}
/*********************************************************************************************************************/
ChimeraTK::ReadAnyGroup Module::readAnyGroup() {
auto recursiveAccessorList = getAccessorListRecursive();
// put push-type transfer elements into a ReadAnyGroup
ChimeraTK::ReadAnyGroup group;
for(auto& accessor : recursiveAccessorList) {
if(accessor.getDirection() == VariableDirection{VariableDirection::feeding, false}) continue;
group.add(accessor.getAppAccessorNoType());
}
group.finalise();
return group;
}
/*********************************************************************************************************************/
void Module::readAll(bool includeReturnChannels) {
auto recursiveAccessorList = getAccessorListRecursive();
// first blockingly read all push-type variables
for(auto& accessor : recursiveAccessorList) {
if(accessor.getMode() != UpdateMode::push) continue;
if(includeReturnChannels) {
if(accessor.getDirection() == VariableDirection{VariableDirection::feeding, false}) continue;
}
else {
if(accessor.getDirection().dir != VariableDirection::consuming) continue;
}
accessor.getAppAccessorNoType().read();
}
// next non-blockingly read the latest values of all poll-type variables
for(auto& accessor : recursiveAccessorList) {
if(accessor.getMode() == UpdateMode::push) continue;
// poll-type accessors cannot have a readback channel
if(accessor.getDirection().dir != VariableDirection::consuming) continue;
accessor.getAppAccessorNoType().readLatest();
}
}
/*********************************************************************************************************************/
void Module::readAllNonBlocking(bool includeReturnChannels) {
auto recursiveAccessorList = getAccessorListRecursive();
for(auto& accessor : recursiveAccessorList) {
if(accessor.getMode() != UpdateMode::push) continue;
if(includeReturnChannels) {
if(accessor.getDirection() == VariableDirection{VariableDirection::feeding, false}) continue;
}
else {
if(accessor.getDirection().dir != VariableDirection::consuming) continue;
}
accessor.getAppAccessorNoType().readNonBlocking();
}
for(auto& accessor : recursiveAccessorList) {
if(accessor.getMode() == UpdateMode::push) continue;
// poll-type accessors cannot have a readback channel
if(accessor.getDirection().dir != VariableDirection::consuming) continue;
accessor.getAppAccessorNoType().readLatest();
}
}
/*********************************************************************************************************************/
void Module::readAllLatest(bool includeReturnChannels) {
auto recursiveAccessorList = getAccessorListRecursive();
for(auto& accessor : recursiveAccessorList) {
if(includeReturnChannels) {
if(accessor.getDirection() == VariableDirection{VariableDirection::feeding, false}) continue;
}
else {
if(accessor.getDirection().dir != VariableDirection::consuming) continue;
}
accessor.getAppAccessorNoType().readLatest();
}
}
/*********************************************************************************************************************/
void Module::writeAll(bool includeReturnChannels) {
auto versionNumber = getCurrentVersionNumber();
auto recursiveAccessorList = getAccessorListRecursive();
for(auto& accessor : recursiveAccessorList) {
if(includeReturnChannels) {
if(accessor.getDirection() == VariableDirection{VariableDirection::consuming, false}) continue;
}
else {
if(accessor.getDirection().dir != VariableDirection::feeding) continue;
}
accessor.getAppAccessorNoType().write(versionNumber);
}
}
/*********************************************************************************************************************/
void Module::writeAllDestructively(bool includeReturnChannels) {
auto versionNumber = getCurrentVersionNumber();
auto recursiveAccessorList = getAccessorListRecursive();
for(auto& accessor : recursiveAccessorList) {
if(includeReturnChannels) {
if(accessor.getDirection() == VariableDirection{VariableDirection::consuming, false}) continue;
}
else {
if(accessor.getDirection().dir != VariableDirection::feeding) continue;
}
accessor.getAppAccessorNoType().writeDestructively(versionNumber);
}
}
/*********************************************************************************************************************/
Module* Module::findApplicationModule() {
if(getModuleType() == ModuleType::ApplicationModule) {
auto* ret = dynamic_cast<ApplicationModule*>(this);
assert(ret != nullptr);
return ret;
}
else if(getModuleType() == ModuleType::Device) {
auto* ret = dynamic_cast<DeviceModule*>(this);
assert(ret != nullptr);
return ret;
}
else if(getModuleType() == ModuleType::VariableGroup) {
auto* owningModule = dynamic_cast<Module*>(getOwner());
assert(owningModule != nullptr);
return owningModule->findApplicationModule();
}
else {
throw ChimeraTK::logic_error(
"EntityOwner::findApplicationModule() called on neither an ApplicationModule nor a VariableGroup.");
}
}
/*********************************************************************************************************************/
std::string Module::getQualifiedName() const {
return ((_owner != nullptr) ? _owner->getQualifiedName() : "") + "/" + _name;
}
/*********************************************************************************************************************/
std::string Module::getFullDescription() const {
if(_owner == nullptr) return _description;
auto ownerDescription = _owner->getFullDescription();
if(ownerDescription == "") return _description;
if(_description == "") return ownerDescription;
return ownerDescription + " - " + _description;
}
/*********************************************************************************************************************/
std::list<EntityOwner*> Module::getInputModulesRecursively(std::list<EntityOwner*> startList) {
if(_owner == nullptr) return {};
return _owner->getInputModulesRecursively(startList);
}
/*********************************************************************************************************************/
ConfigReader& Module::appConfig() {
size_t nConfigReaders = 0;
ConfigReader* instance = nullptr;
for(auto* mod : Application::getInstance().getSubmoduleListRecursive()) {
if(!dynamic_cast<ConfigReader*>(mod)) continue;
++nConfigReaders;
instance = dynamic_cast<ConfigReader*>(mod);
}
if(nConfigReaders != 1) {
std::string message = "ApplicationModule::appConfig() called but " + std::to_string(nConfigReaders) +
" instances of ChimeraTK::ConfigReader have been found.";
// Printing the message as well; there is a situation when running under Boost::Test where this
// is caught by Boost and causes a weird destructor message from AppBase.cc instead with no means of
// finding out the actual error
std::cerr << message << std::endl;
throw ChimeraTK::logic_error(message);
}
return *instance;
}
/*********************************************************************************************************************/
} /* namespace ChimeraTK */