Newer
Older
Martin Christoph Hierholzer
committed
/*
* Application.cc
*
* Created on: Jun 10, 2016
* Author: Martin Hierholzer
*/
#include <string>
#include <thread>
Martin Christoph Hierholzer
committed
#include <exception>
Martin Christoph Hierholzer
committed
#include <boost/fusion/container/map.hpp>
Martin Christoph Hierholzer
committed
#include <libxml++/libxml++.h>
Martin Christoph Hierholzer
committed
#include <mtca4u/BackendFactory.h>
Martin Christoph Hierholzer
committed
#include "Application.h"
#include "ApplicationModule.h"
Martin Christoph Hierholzer
committed
#include "ThreadedFanOut.h"
#include "ConsumingFanOut.h"
#include "FeedingFanOut.h"
#include "TriggerFanOut.h"
Martin Christoph Hierholzer
committed
#include "VariableNetworkNode.h"
Martin Christoph Hierholzer
committed
#include "ScalarAccessor.h"
#include "ArrayAccessor.h"
#include "ConstantAccessor.h"
Martin Christoph Hierholzer
committed
using namespace ChimeraTK;
Martin Christoph Hierholzer
committed
/*********************************************************************************************************************/
Martin Christoph Hierholzer
committed
void Application::initialise() {
// call the user-defined defineConnections() function which describes the structure of the application
defineConnections();
// connect any unconnected accessors with constant values
processUnconnectedNodes();
// realise the connections between variable accessors as described in the initialise() function
makeConnections();
}
/*********************************************************************************************************************/
void Application::processUnconnectedNodes() {
Martin Christoph Hierholzer
committed
for(auto &module : overallModuleList) {
Martin Christoph Hierholzer
committed
for(auto &accessor : module->getAccessorList()) {
Martin Christoph Hierholzer
committed
if(!accessor.hasOwner()) {
std::cerr << "*** Warning: Variable '" << accessor.getName() << "' is not connected. "
Martin Christoph Hierholzer
committed
"Reading will always result in 0, writing will be ignored." << std::endl;
networkList.emplace_back();
Martin Christoph Hierholzer
committed
networkList.back().addNode(accessor);
Martin Christoph Hierholzer
committed
bool makeFeeder = !(networkList.back().hasFeedingNode());
Martin Christoph Hierholzer
committed
size_t length = accessor.getNumberOfElements();
Martin Christoph Hierholzer
committed
Martin Christoph Hierholzer
committed
if(accessor.getValueType() == typeid(int8_t)) {
Martin Christoph Hierholzer
committed
constantList.emplace_back(VariableNetworkNode::makeConstant<int8_t>(makeFeeder, 0, length));
}
Martin Christoph Hierholzer
committed
else if(accessor.getValueType() == typeid(uint8_t)) {
Martin Christoph Hierholzer
committed
constantList.emplace_back(VariableNetworkNode::makeConstant<uint8_t>(makeFeeder, 0, length));
}
Martin Christoph Hierholzer
committed
else if(accessor.getValueType() == typeid(int16_t)) {
Martin Christoph Hierholzer
committed
constantList.emplace_back(VariableNetworkNode::makeConstant<int16_t>(makeFeeder, 0, length));
}
Martin Christoph Hierholzer
committed
else if(accessor.getValueType() == typeid(uint16_t)) {
Martin Christoph Hierholzer
committed
constantList.emplace_back(VariableNetworkNode::makeConstant<uint16_t>(makeFeeder, 0, length));
}
Martin Christoph Hierholzer
committed
else if(accessor.getValueType() == typeid(int32_t)) {
Martin Christoph Hierholzer
committed
constantList.emplace_back(VariableNetworkNode::makeConstant<int32_t>(makeFeeder, 0, length));
}
Martin Christoph Hierholzer
committed
else if(accessor.getValueType() == typeid(uint32_t)) {
Martin Christoph Hierholzer
committed
constantList.emplace_back(VariableNetworkNode::makeConstant<uint32_t>(makeFeeder, 0, length));
}
Martin Christoph Hierholzer
committed
else if(accessor.getValueType() == typeid(float)) {
Martin Christoph Hierholzer
committed
constantList.emplace_back(VariableNetworkNode::makeConstant<float>(makeFeeder, 0, length));
}
Martin Christoph Hierholzer
committed
else if(accessor.getValueType() == typeid(double)) {
Martin Christoph Hierholzer
committed
constantList.emplace_back(VariableNetworkNode::makeConstant<double>(makeFeeder, 0, length));
}
else {
throw std::invalid_argument("Unknown value type.");
}
networkList.back().addNode(constantList.back());
}
}
}
}
Martin Christoph Hierholzer
committed
Martin Christoph Hierholzer
committed
/*********************************************************************************************************************/
void Application::checkConnections() {
// check all networks for validity
for(auto &network : networkList) {
network.check();
}
// check if all accessors are connected
Martin Christoph Hierholzer
committed
for(auto &module : overallModuleList) {
Martin Christoph Hierholzer
committed
for(auto &accessor : module->getAccessorList()) {
Martin Christoph Hierholzer
committed
if(!accessor.hasOwner()) {
throw std::invalid_argument("The accessor '"+accessor.getName()+"' of the module '"+module->getName()+
Martin Christoph Hierholzer
committed
"' was not connected!");
}
}
}
}
/*********************************************************************************************************************/
void Application::run() {
Martin Christoph Hierholzer
committed
// check if the application name has been set
if(applicationName == "") {
throw ApplicationExceptionWithID<ApplicationExceptionID::illegalParameter>(
"Error: An instance of Application must have its applicationName set.");
}
Martin Christoph Hierholzer
committed
// start the necessary threads for the FanOuts etc.
for(auto &internalModule : internalModuleList) {
internalModule->activate();
Martin Christoph Hierholzer
committed
}
Martin Christoph Hierholzer
committed
Martin Christoph Hierholzer
committed
// read all input variables once, to set the startup value e.g. coming from the config file
// (without triggering an action inside the application)
Martin Christoph Hierholzer
committed
for(auto &module : overallModuleList) {
Martin Christoph Hierholzer
committed
for(auto &variable : module->getAccessorList()) {
Martin Christoph Hierholzer
committed
if(variable.getDirection() == VariableDirection::consuming) {
variable.getAppAccessorNoType().readNonBlocking();
Martin Christoph Hierholzer
committed
}
}
}
Martin Christoph Hierholzer
committed
// start the threads for the modules
Martin Christoph Hierholzer
committed
for(auto &module : overallModuleList) {
Martin Christoph Hierholzer
committed
module->run();
}
}
/*********************************************************************************************************************/
Martin Christoph Hierholzer
committed
void Application::shutdown() {
// deactivate the FanOuts first, since they have running threads inside accessing the modules etc.
// (note: the modules are members of the Application implementation and thus get destroyed after this destructor)
for(auto &internalModule : internalModuleList) {
internalModule->deactivate();
Martin Christoph Hierholzer
committed
}
// next deactivate the modules, as they have running threads inside as well
Martin Christoph Hierholzer
committed
for(auto &module : overallModuleList) {
Martin Christoph Hierholzer
committed
module->terminate();
}
ApplicationBase::shutdown();
}
/*********************************************************************************************************************/
Martin Christoph Hierholzer
committed
void Application::generateXML() {
Martin Christoph Hierholzer
committed
// define the connections
defineConnections();
// also search for unconnected nodes - this is here only executed to print the warnings
processUnconnectedNodes();
Martin Christoph Hierholzer
committed
Martin Christoph Hierholzer
committed
// check if the application name has been set
if(applicationName == "") {
throw ApplicationExceptionWithID<ApplicationExceptionID::illegalParameter>(
"Error: An instance of Application must have its applicationName set.");
}
Martin Christoph Hierholzer
committed
// create XML document with root node
xmlpp::Document doc;
Martin Christoph Hierholzer
committed
xmlpp::Element *rootElement = doc.create_root_node("application", "https://github.com/ChimeraTK/ApplicationCore");
rootElement->set_attribute("name",applicationName);
Martin Christoph Hierholzer
committed
Martin Christoph Hierholzer
committed
for(auto &network : networkList) {
Martin Christoph Hierholzer
committed
// perform checks
network.check();
Martin Christoph Hierholzer
committed
// create xml code for the feeder (if it is a control system node)
Martin Christoph Hierholzer
committed
auto feeder = network.getFeedingNode();
Martin Christoph Hierholzer
committed
feeder.createXML(rootElement);
// create xml code for the consumers
for(auto &consumer : network.getConsumingNodes()) {
consumer.createXML(rootElement);
Martin Christoph Hierholzer
committed
}
Martin Christoph Hierholzer
committed
}
Martin Christoph Hierholzer
committed
doc.write_to_file_formatted(applicationName+".xml");
Martin Christoph Hierholzer
committed
}
/*********************************************************************************************************************/
Martin Christoph Hierholzer
committed
VariableNetwork& Application::connect(VariableNetworkNode a, VariableNetworkNode b) {
// if one of the nodes has the value type AnyType, set it to the type of the other
Martin Christoph Hierholzer
committed
// if both are AnyType, nothing changes.
if(a.getValueType() == typeid(AnyType)) {
a.setValueType(b.getValueType());
}
else if(b.getValueType() == typeid(AnyType)) {
b.setValueType(a.getValueType());
}
// if one of the nodes has not yet a defined number of elements, set it to the number of elements of the other.
// if both are undefined, nothing changes.
if(a.getNumberOfElements() == 0) {
a.setNumberOfElements(b.getNumberOfElements());
}
else if(b.getNumberOfElements() == 0) {
b.setNumberOfElements(a.getNumberOfElements());
}
if(a.getNumberOfElements() != b.getNumberOfElements()) {
throw ApplicationExceptionWithID<ApplicationExceptionID::illegalParameter>(
"Error: Cannot connect array variables with difference number of elements!");
}
Martin Christoph Hierholzer
committed
// if both nodes already have an owner, we are done
if(a.hasOwner() && b.hasOwner()) {
assert( &(a.getOwner()) == &(b.getOwner()) ); /// @todo TODO merge networks?
}
Martin Christoph Hierholzer
committed
// add b to the existing network of a
Martin Christoph Hierholzer
committed
else if(a.hasOwner()) {
a.getOwner().addNode(b);
}
Martin Christoph Hierholzer
committed
// add a to the existing network of b
Martin Christoph Hierholzer
committed
else if(b.hasOwner()) {
b.getOwner().addNode(a);
}
Martin Christoph Hierholzer
committed
// create new network
Martin Christoph Hierholzer
committed
else {
networkList.emplace_back();
networkList.back().addNode(a);
networkList.back().addNode(b);
}
Martin Christoph Hierholzer
committed
return a.getOwner();
Martin Christoph Hierholzer
committed
}
Martin Christoph Hierholzer
committed
/*********************************************************************************************************************/
Martin Christoph Hierholzer
committed
template<typename UserType>
boost::shared_ptr<mtca4u::NDRegisterAccessor<UserType>> Application::createDeviceVariable(const std::string &deviceAlias,
Martin Christoph Hierholzer
committed
const std::string ®isterName, VariableDirection direction, UpdateMode mode, size_t nElements) {
Martin Christoph Hierholzer
committed
Martin Christoph Hierholzer
committed
// open device if needed
if(deviceMap.count(deviceAlias) == 0) {
deviceMap[deviceAlias] = mtca4u::BackendFactory::getInstance().createBackend(deviceAlias);
if(!deviceMap[deviceAlias]->isOpen()) deviceMap[deviceAlias]->open();
Martin Christoph Hierholzer
committed
}
Martin Christoph Hierholzer
committed
Martin Christoph Hierholzer
committed
// use wait_for_new_data mode if push update mode was requested
Martin Christoph Hierholzer
committed
mtca4u::AccessModeFlags flags{};
Martin Christoph Hierholzer
committed
if(mode == UpdateMode::push && direction == VariableDirection::consuming) flags = {AccessMode::wait_for_new_data};
Martin Christoph Hierholzer
committed
Martin Christoph Hierholzer
committed
// return the register accessor from the device
return deviceMap[deviceAlias]->getRegisterAccessor<UserType>(registerName, nElements, 0, flags);
Martin Christoph Hierholzer
committed
}
/*********************************************************************************************************************/
Martin Christoph Hierholzer
committed
template<typename UserType>
Martin Christoph Hierholzer
committed
boost::shared_ptr<mtca4u::NDRegisterAccessor<UserType>> Application::createProcessVariable(VariableNetworkNode const &node) {
Martin Christoph Hierholzer
committed
// determine the SynchronizationDirection
SynchronizationDirection dir;
Martin Christoph Hierholzer
committed
if(node.getDirection() == VariableDirection::feeding) {
Martin Christoph Hierholzer
committed
dir = SynchronizationDirection::controlSystemToDevice;
Martin Christoph Hierholzer
committed
}
else {
Martin Christoph Hierholzer
committed
dir = SynchronizationDirection::deviceToControlSystem;
Martin Christoph Hierholzer
committed
}
Martin Christoph Hierholzer
committed
Martin Christoph Hierholzer
committed
// create the ProcessScalar for the proper UserType
Martin Christoph Hierholzer
committed
return _processVariableManager->createProcessArray<UserType>(dir, node.getPublicName(), node.getNumberOfElements(),
node.getOwner().getUnit(), node.getOwner().getDescription());
Martin Christoph Hierholzer
committed
}
Martin Christoph Hierholzer
committed
/*********************************************************************************************************************/
Martin Christoph Hierholzer
committed
template<typename UserType>
std::pair< boost::shared_ptr<mtca4u::NDRegisterAccessor<UserType>>, boost::shared_ptr<mtca4u::NDRegisterAccessor<UserType>> >
Application::createApplicationVariable(size_t nElements, const std::string &name) {
Martin Christoph Hierholzer
committed
// create the ProcessScalar for the proper UserType
return createSynchronizedProcessArray<UserType>(nElements, name);
Martin Christoph Hierholzer
committed
}
Martin Christoph Hierholzer
committed
Martin Christoph Hierholzer
committed
/*********************************************************************************************************************/
void Application::makeConnections() {
Martin Christoph Hierholzer
committed
// run checks first
checkConnections();
Martin Christoph Hierholzer
committed
// make the connections for all networks
for(auto &network : networkList) {
makeConnectionsForNetwork(network);
}
Martin Christoph Hierholzer
committed
Martin Christoph Hierholzer
committed
}
Martin Christoph Hierholzer
committed
Martin Christoph Hierholzer
committed
/*********************************************************************************************************************/
Martin Christoph Hierholzer
committed
Martin Christoph Hierholzer
committed
void Application::dumpConnections() {
std::cout << "==== List of all variable connections of the current Application ====" << std::endl;
Martin Christoph Hierholzer
committed
for(auto &network : networkList) {
network.dump();
}
std::cout << "=====================================================================" << std::endl;
Martin Christoph Hierholzer
committed
}
/*********************************************************************************************************************/
Martin Christoph Hierholzer
committed
void Application::makeConnectionsForNetwork(VariableNetwork &network) {
Martin Christoph Hierholzer
committed
Martin Christoph Hierholzer
committed
// if the network has been created already, do nothing
if(network.isCreated()) return;
Martin Christoph Hierholzer
committed
Martin Christoph Hierholzer
committed
// if the trigger type is external, create the trigger first
if(network.getFeedingNode().hasExternalTrigger()) {
VariableNetwork &dependency = network.getFeedingNode().getExternalTrigger().getOwner();
Martin Christoph Hierholzer
committed
if(!dependency.isCreated()) makeConnectionsForNetwork(dependency);
Martin Christoph Hierholzer
committed
}
Martin Christoph Hierholzer
committed
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
// defer actual network creation to templated function
// @todo TODO replace with boost::mpl::for_each loop!
if(network.getValueType() == typeid(int8_t)) {
typedMakeConnection<int8_t>(network);
}
else if(network.getValueType() == typeid(uint8_t)) {
typedMakeConnection<uint8_t>(network);
}
else if(network.getValueType() == typeid(int16_t)) {
typedMakeConnection<int16_t>(network);
}
else if(network.getValueType() == typeid(uint16_t)) {
typedMakeConnection<uint16_t>(network);
}
else if(network.getValueType() == typeid(int32_t)) {
typedMakeConnection<int32_t>(network);
}
else if(network.getValueType() == typeid(uint32_t)) {
typedMakeConnection<uint32_t>(network);
}
else if(network.getValueType() == typeid(float)) {
typedMakeConnection<float>(network);
}
else if(network.getValueType() == typeid(double)) {
typedMakeConnection<double>(network);
}
// mark the network as created
network.markCreated();
Martin Christoph Hierholzer
committed
}
/*********************************************************************************************************************/
template<typename UserType>
void Application::typedMakeConnection(VariableNetwork &network) {
bool connectionMade = false; // to check the logic...
size_t nNodes = network.countConsumingNodes()+1;
Martin Christoph Hierholzer
committed
auto feeder = network.getFeedingNode();
Martin Christoph Hierholzer
committed
auto consumers = network.getConsumingNodes();
Martin Christoph Hierholzer
committed
bool useExternalTrigger = network.getTriggerType() == VariableNetwork::TriggerType::external;
Martin Christoph Hierholzer
committed
bool useFeederTrigger = network.getTriggerType() == VariableNetwork::TriggerType::feeder;
Martin Christoph Hierholzer
committed
Martin Christoph Hierholzer
committed
// 1st case: the feeder requires a fixed implementation
if(feeder.hasImplementation()) {
// Create feeding implementation. Note: though the implementation is derived from the feeder, it will be used as
// the implementation of the (or one of the) consumer. Logically, implementations are always pairs of
// implementations (sender and receiver), but in this case the feeder already has a fixed implementation pair.
// So our feedingImpl will contain the consumer-end of the implementation pair. This is the reason why the
// functions createProcessScalar() and createDeviceAccessor() get the VariableDirection::consuming.
boost::shared_ptr<mtca4u::NDRegisterAccessor<UserType>> feedingImpl;
Martin Christoph Hierholzer
committed
if(feeder.getType() == NodeType::Device) {
feedingImpl = createDeviceVariable<UserType>(feeder.getDeviceAlias(), feeder.getRegisterName(),
Martin Christoph Hierholzer
committed
VariableDirection::consuming, feeder.getMode(), feeder.getNumberOfElements());
Martin Christoph Hierholzer
committed
}
Martin Christoph Hierholzer
committed
else if(feeder.getType() == NodeType::ControlSystem) {
Martin Christoph Hierholzer
committed
feedingImpl = createProcessVariable<UserType>(feeder);
Martin Christoph Hierholzer
committed
}
Martin Christoph Hierholzer
committed
else if(feeder.getType() == NodeType::Constant) {
Martin Christoph Hierholzer
committed
feedingImpl = feeder.getConstAccessor<UserType>();
Martin Christoph Hierholzer
committed
assert(feedingImpl != nullptr);
}
else {
throw ApplicationExceptionWithID<ApplicationExceptionID::illegalParameter>("Unexpected node type!");
}
Martin Christoph Hierholzer
committed
// if we just have two nodes, directly connect them
Martin Christoph Hierholzer
committed
if(nNodes == 2 && !useExternalTrigger) {
Martin Christoph Hierholzer
committed
auto consumer = consumers.front();
Martin Christoph Hierholzer
committed
if(consumer.getType() == NodeType::Application) {
Martin Christoph Hierholzer
committed
consumer.getAppAccessor<UserType>().replace(feedingImpl);
Martin Christoph Hierholzer
committed
connectionMade = true;
}
Martin Christoph Hierholzer
committed
else if(consumer.getType() == NodeType::Device) {
auto consumingImpl = createDeviceVariable<UserType>(consumer.getDeviceAlias(), consumer.getRegisterName(),
Martin Christoph Hierholzer
committed
VariableDirection::feeding, consumer.getMode(), consumer.getNumberOfElements());
Martin Christoph Hierholzer
committed
// connect the Device with e.g. a ControlSystem node via a ThreadedFanOut
auto fanOut = boost::make_shared<ThreadedFanOut<UserType>>(feedingImpl);
Martin Christoph Hierholzer
committed
fanOut->addSlave(consumingImpl);
internalModuleList.push_back(fanOut);
Martin Christoph Hierholzer
committed
connectionMade = true;
}
Martin Christoph Hierholzer
committed
else if(consumer.getType() == NodeType::ControlSystem) {
Martin Christoph Hierholzer
committed
auto consumingImpl = createProcessVariable<UserType>(consumer);
Martin Christoph Hierholzer
committed
// connect the ControlSystem with e.g. a Device node via an ThreadedFanOut
auto fanOut = boost::make_shared<ThreadedFanOut<UserType>>(feedingImpl);
Martin Christoph Hierholzer
committed
fanOut->addSlave(consumingImpl);
internalModuleList.push_back(fanOut);
Martin Christoph Hierholzer
committed
connectionMade = true;
Martin Christoph Hierholzer
committed
}
Martin Christoph Hierholzer
committed
else if(consumer.getType() == NodeType::TriggerReceiver) {
consumer.getTriggerReceiver().getOwner().setExternalTriggerImpl(feedingImpl);
Martin Christoph Hierholzer
committed
connectionMade = true;
}
Martin Christoph Hierholzer
committed
else {
throw ApplicationExceptionWithID<ApplicationExceptionID::illegalParameter>("Unexpected node type!");
}
}
Martin Christoph Hierholzer
committed
else { /* !(nNodes == 2 && !useExternalTrigger) */
Martin Christoph Hierholzer
committed
// create the right FanOut type
boost::shared_ptr<FanOut<UserType>> fanOut;
Martin Christoph Hierholzer
committed
boost::shared_ptr<ConsumingFanOut<UserType>> consumingFanOut;
Martin Christoph Hierholzer
committed
if(useExternalTrigger) {
// if external trigger is enabled, use externally triggered threaded FanOut
Martin Christoph Hierholzer
committed
auto triggerNode = feeder.getExternalTrigger();
auto triggerFanOut = triggerMap[triggerNode.getUniqueId()];
if(!triggerFanOut) {
Martin Christoph Hierholzer
committed
triggerFanOut = boost::make_shared<TriggerFanOut>(network.getExternalTriggerImpl());
triggerMap[triggerNode.getUniqueId()] = triggerFanOut;
internalModuleList.push_back(triggerFanOut);
}
fanOut = triggerFanOut->addNetwork(feedingImpl);
Martin Christoph Hierholzer
committed
}
Martin Christoph Hierholzer
committed
else if(useFeederTrigger) {
// if the trigger is provided by the pushing feeder, use the treaded version of the FanOut to distribute
// new values immediately to all consumers.
Martin Christoph Hierholzer
committed
auto threadedFanOut = boost::make_shared<ThreadedFanOut<UserType>>(feedingImpl);
internalModuleList.push_back(threadedFanOut);
fanOut = threadedFanOut;
Martin Christoph Hierholzer
committed
}
else {
if(!network.hasApplicationConsumer()) {
throw ApplicationExceptionWithID<ApplicationExceptionID::illegalParameter>("No application node in the network but no trigger!");
}
Martin Christoph Hierholzer
committed
consumingFanOut = boost::make_shared<ConsumingFanOut<UserType>>(feedingImpl);
fanOut = consumingFanOut;
}
// add all consumers to the FanOut
Martin Christoph Hierholzer
committed
for(auto &consumer : consumers) {
Martin Christoph Hierholzer
committed
if(consumer.getType() == NodeType::Application) {
Martin Christoph Hierholzer
committed
if(consumingFanOut) {
Martin Christoph Hierholzer
committed
consumer.getAppAccessor<UserType>().replace(consumingFanOut);
Martin Christoph Hierholzer
committed
consumingFanOut.reset();
Martin Christoph Hierholzer
committed
}
else {
Martin Christoph Hierholzer
committed
auto impls = createApplicationVariable<UserType>(consumer.getNumberOfElements(), consumer.getName());
Martin Christoph Hierholzer
committed
fanOut->addSlave(impls.first);
Martin Christoph Hierholzer
committed
consumer.getAppAccessor<UserType>().replace(impls.second);
Martin Christoph Hierholzer
committed
}
Martin Christoph Hierholzer
committed
}
Martin Christoph Hierholzer
committed
else if(consumer.getType() == NodeType::ControlSystem) {
Martin Christoph Hierholzer
committed
auto impl = createProcessVariable<UserType>(consumer);
Martin Christoph Hierholzer
committed
fanOut->addSlave(impl);
Martin Christoph Hierholzer
committed
}
Martin Christoph Hierholzer
committed
else if(consumer.getType() == NodeType::Device) {
auto impl = createDeviceVariable<UserType>(consumer.getDeviceAlias(), consumer.getRegisterName(),
Martin Christoph Hierholzer
committed
VariableDirection::feeding, consumer.getMode(), consumer.getNumberOfElements());
Martin Christoph Hierholzer
committed
fanOut->addSlave(impl);
Martin Christoph Hierholzer
committed
}
Martin Christoph Hierholzer
committed
else if(consumer.getType() == NodeType::TriggerReceiver) {
Martin Christoph Hierholzer
committed
auto impls = createApplicationVariable<UserType>(consumer.getNumberOfElements(), consumer.getName());
Martin Christoph Hierholzer
committed
fanOut->addSlave(impls.first);
consumer.getTriggerReceiver().getOwner().setExternalTriggerImpl(impls.second);
Martin Christoph Hierholzer
committed
}
Martin Christoph Hierholzer
committed
else {
throw ApplicationExceptionWithID<ApplicationExceptionID::illegalParameter>("Unexpected node type!");
Martin Christoph Hierholzer
committed
}
Martin Christoph Hierholzer
committed
}
Martin Christoph Hierholzer
committed
connectionMade = true;
Martin Christoph Hierholzer
committed
}
Martin Christoph Hierholzer
committed
}
// 2nd case: the feeder does not require a fixed implementation
Martin Christoph Hierholzer
committed
else { /* !feeder.hasImplementation() */
Martin Christoph Hierholzer
committed
// we should be left with an application feeder node
Martin Christoph Hierholzer
committed
if(feeder.getType() != NodeType::Application) {
Martin Christoph Hierholzer
committed
throw ApplicationExceptionWithID<ApplicationExceptionID::illegalParameter>("Unexpected node type!");
}
Martin Christoph Hierholzer
committed
assert(!useExternalTrigger);
Martin Christoph Hierholzer
committed
// if we just have two nodes, directly connect them
if(nNodes == 2) {
Martin Christoph Hierholzer
committed
auto consumer = consumers.front();
Martin Christoph Hierholzer
committed
if(consumer.getType() == NodeType::Application) {
Martin Christoph Hierholzer
committed
auto impls = createApplicationVariable<UserType>(consumer.getNumberOfElements(), feeder.getName());
feeder.getAppAccessor<UserType>().replace(impls.first);
consumer.getAppAccessor<UserType>().replace(impls.second);
Martin Christoph Hierholzer
committed
connectionMade = true;
}
Martin Christoph Hierholzer
committed
else if(consumer.getType() == NodeType::ControlSystem) {
Martin Christoph Hierholzer
committed
auto impl = createProcessVariable<UserType>(consumer);
Martin Christoph Hierholzer
committed
feeder.getAppAccessor<UserType>().replace(impl);
Martin Christoph Hierholzer
committed
connectionMade = true;
}
Martin Christoph Hierholzer
committed
else if(consumer.getType() == NodeType::Device) {
auto impl = createDeviceVariable<UserType>(consumer.getDeviceAlias(), consumer.getRegisterName(),
Martin Christoph Hierholzer
committed
VariableDirection::feeding, consumer.getMode(), consumer.getNumberOfElements());
Martin Christoph Hierholzer
committed
feeder.getAppAccessor<UserType>().replace(impl);
Martin Christoph Hierholzer
committed
connectionMade = true;
}
Martin Christoph Hierholzer
committed
else if(consumer.getType() == NodeType::TriggerReceiver) {
Martin Christoph Hierholzer
committed
auto impls = createApplicationVariable<UserType>(consumer.getNumberOfElements(), feeder.getName());
feeder.getAppAccessor<UserType>().replace(impls.first);
consumer.getTriggerReceiver().getOwner().setExternalTriggerImpl(impls.second);
Martin Christoph Hierholzer
committed
connectionMade = true;
}
Martin Christoph Hierholzer
committed
else if(consumer.getType() == NodeType::Constant) {
Martin Christoph Hierholzer
committed
auto impl = consumer.getConstAccessor<UserType>();
feeder.getAppAccessor<UserType>().replace(impl);
Martin Christoph Hierholzer
committed
connectionMade = true;
}
Martin Christoph Hierholzer
committed
else {
throw ApplicationExceptionWithID<ApplicationExceptionID::illegalParameter>("Unexpected node type!");
}
}
else {
// create FanOut and use it as the feeder implementation
Martin Christoph Hierholzer
committed
auto fanOut = boost::make_shared<FeedingFanOut<UserType>>(feeder.getName(), feeder.getUnit(),
Martin Christoph Hierholzer
committed
feeder.getDescription(), feeder.getNumberOfElements());
Martin Christoph Hierholzer
committed
feeder.getAppAccessor<UserType>().replace(fanOut);
Martin Christoph Hierholzer
committed
for(auto &consumer : consumers) {
Martin Christoph Hierholzer
committed
if(consumer.getType() == NodeType::Application) {
Martin Christoph Hierholzer
committed
auto impls = createApplicationVariable<UserType>(consumer.getNumberOfElements(), feeder.getName());
Martin Christoph Hierholzer
committed
fanOut->addSlave(impls.first);
Martin Christoph Hierholzer
committed
consumer.getAppAccessor<UserType>().replace(impls.second);
Martin Christoph Hierholzer
committed
}
Martin Christoph Hierholzer
committed
else if(consumer.getType() == NodeType::ControlSystem) {
Martin Christoph Hierholzer
committed
auto impl = createProcessVariable<UserType>(consumer);
Martin Christoph Hierholzer
committed
fanOut->addSlave(impl);
}
Martin Christoph Hierholzer
committed
else if(consumer.getType() == NodeType::Device) {
auto impl = createDeviceVariable<UserType>(consumer.getDeviceAlias(), consumer.getRegisterName(),
Martin Christoph Hierholzer
committed
VariableDirection::feeding, consumer.getMode(), consumer.getNumberOfElements());
Martin Christoph Hierholzer
committed
fanOut->addSlave(impl);
}
Martin Christoph Hierholzer
committed
else if(consumer.getType() == NodeType::TriggerReceiver) {
Martin Christoph Hierholzer
committed
auto impls = createApplicationVariable<UserType>(consumer.getNumberOfElements(), feeder.getName());
Martin Christoph Hierholzer
committed
fanOut->addSlave(impls.first);
consumer.getTriggerReceiver().getOwner().setExternalTriggerImpl(impls.second);
Martin Christoph Hierholzer
committed
}
Martin Christoph Hierholzer
committed
else {
throw ApplicationExceptionWithID<ApplicationExceptionID::illegalParameter>("Unexpected node type!");
}
}
connectionMade = true;
Martin Christoph Hierholzer
committed
}
}
Martin Christoph Hierholzer
committed
Martin Christoph Hierholzer
committed
if(!connectionMade) {
throw ApplicationExceptionWithID<ApplicationExceptionID::notYetImplemented>(
Martin Christoph Hierholzer
committed
"The variable network cannot be handled. Implementation missing!");
Martin Christoph Hierholzer
committed
}
Martin Christoph Hierholzer
committed
}
/*********************************************************************************************************************/
Martin Christoph Hierholzer
committed
VariableNetwork& Application::createNetwork() {
networkList.emplace_back();
return networkList.back();
}
Martin Christoph Hierholzer
committed
/*********************************************************************************************************************/
Application& Application::getInstance() {
return dynamic_cast<Application&>(ApplicationBase::getInstance());
}