Newer
Older
Martin Christoph Hierholzer
committed
/*
* VariableNetworkNode.cc
*
* Created on: Jun 23, 2016
* Author: Martin Hierholzer
*/
#include <libxml++/libxml++.h>
#include "VariableNetworkNode.h"
#include "VariableNetwork.h"
#include "Accessor.h"
#include "Application.h"
namespace ChimeraTK {
/*********************************************************************************************************************/
Martin Christoph Hierholzer
committed
VariableNetworkNode::VariableNetworkNode(const VariableNetworkNode &other)
: pdata(other.pdata)
Martin Christoph Hierholzer
committed
{}
/*********************************************************************************************************************/
Martin Christoph Hierholzer
committed
VariableNetworkNode& VariableNetworkNode::operator=(const VariableNetworkNode &rightHandSide) {
pdata = rightHandSide.pdata;
return *this;
}
/*********************************************************************************************************************/
VariableNetworkNode::VariableNetworkNode(AccessorBase &accessor)
: pdata(new data)
{
pdata->type = NodeType::Application;
pdata->mode = accessor.getUpdateMode();
pdata->direction = accessor.getDirection();
pdata->valueType = &(accessor.getValueType());
pdata->unit = accessor.getUnit();
pdata->appNode = &accessor;
}
/*********************************************************************************************************************/
Martin Christoph Hierholzer
committed
VariableNetworkNode::VariableNetworkNode(const std::string &devAlias, const std::string ®Name, UpdateMode mod,
VariableDirection dir, const std::type_info &valTyp)
Martin Christoph Hierholzer
committed
: pdata(new data)
{
pdata->type = NodeType::Device;
pdata->mode = mod;
pdata->direction = dir;
pdata->valueType = &valTyp;
pdata->deviceAlias = devAlias;
pdata->registerName = regName;
}
Martin Christoph Hierholzer
committed
Martin Christoph Hierholzer
committed
/*********************************************************************************************************************/
Martin Christoph Hierholzer
committed
VariableNetworkNode::VariableNetworkNode(std::string pubName, VariableDirection dir, const std::type_info &valTyp)
Martin Christoph Hierholzer
committed
: pdata(new data)
{
pdata->type = NodeType::ControlSystem;
pdata->mode = UpdateMode::push;
pdata->direction = dir;
pdata->valueType = &valTyp;
pdata->publicName = pubName;
}
Martin Christoph Hierholzer
committed
/*********************************************************************************************************************/
VariableNetworkNode::VariableNetworkNode(VariableNetwork *networkToTrigger)
Martin Christoph Hierholzer
committed
: pdata(new data)
{
pdata->type = NodeType::TriggerReceiver;
pdata->direction = VariableDirection::consuming;
pdata->triggerReceiver = networkToTrigger;
}
Martin Christoph Hierholzer
committed
/*********************************************************************************************************************/
void VariableNetworkNode::setOwner(VariableNetwork *net) {
Martin Christoph Hierholzer
committed
assert(pdata->network == nullptr);
assert(pdata->type != NodeType::invalid);
pdata->network = net;
Martin Christoph Hierholzer
committed
}
/*********************************************************************************************************************/
Martin Christoph Hierholzer
committed
bool VariableNetworkNode::hasImplementation() const {
Martin Christoph Hierholzer
committed
return pdata->type == NodeType::Device || pdata->type == NodeType::ControlSystem;
Martin Christoph Hierholzer
committed
}
/*********************************************************************************************************************/
void VariableNetworkNode::dump() const {
Martin Christoph Hierholzer
committed
if(pdata->type == NodeType::Application) std::cout << " type = Application";
if(pdata->type == NodeType::ControlSystem) std::cout << " type = ControlSystem ('" << pdata->publicName << "')";
if(pdata->type == NodeType::Device) std::cout << " type = Device (" << pdata->deviceAlias << ": " << pdata->registerName << ")";
if(pdata->type == NodeType::TriggerReceiver) std::cout << " type = TriggerReceiver";
if(pdata->type == NodeType::invalid) std::cout << " type = **invalid**";
Martin Christoph Hierholzer
committed
Martin Christoph Hierholzer
committed
if(pdata->mode == UpdateMode::push) std::cout << " pushing";
if(pdata->mode == UpdateMode::poll) std::cout << " polling";
Martin Christoph Hierholzer
committed
Martin Christoph Hierholzer
committed
std::cout << " data type: " << pdata->valueType->name();
Martin Christoph Hierholzer
committed
std::cout << std::endl;
Martin Christoph Hierholzer
committed
}
/*********************************************************************************************************************/
void VariableNetworkNode::createXML(xmlpp::Element *rootElement) const {
Martin Christoph Hierholzer
committed
if(pdata->type != NodeType::ControlSystem) return;
Martin Christoph Hierholzer
committed
// Create the directory for the path name in the XML document with all parent directories, if not yet existing:
// First split the publication name into components and loop over each component. For each component, try to find
// the directory node and create it it does not exist. After the loop, the "current" will point to the Element
// representing the directory.
// strip the variable name from the path
Martin Christoph Hierholzer
committed
mtca4u::RegisterPath directory(pdata->publicName);
Martin Christoph Hierholzer
committed
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
directory--;
// the namespace map is needed to properly refer to elements with an xpath expression in xmlpp::Element::find()
/// @todo TODO move this somewhere else, or at least take the namespace URI from a common place!
xmlpp::Node::PrefixNsMap nsMap{{"ac", "https://github.com/ChimeraTK/ApplicationCore"}};
// go through each directory path component
xmlpp::Element *current = rootElement;
for(auto pathComponent : directory.getComponents()) {
// find directory for this path component in the current directory
std::string xpath = std::string("ac:directory[@name='")+pathComponent+std::string("']");
auto list = current->find(xpath, nsMap);
if(list.size() == 0) { // not found: create it
xmlpp::Element *newChild = current->add_child("directory");
newChild->set_attribute("name",pathComponent);
current = newChild;
}
else {
assert(list.size() == 1);
current = dynamic_cast<xmlpp::Element*>(list[0]);
assert(current != nullptr);
}
}
// now add the variable to the directory
xmlpp::Element *variable = current->add_child("variable");
Martin Christoph Hierholzer
committed
mtca4u::RegisterPath pathName(pdata->publicName);
Martin Christoph Hierholzer
committed
auto pathComponents = pathName.getComponents();
// set the name attribute
variable->set_attribute("name",pathComponents[pathComponents.size()-1]);
// add sub-element containing the data type
std::string dataTypeName{"unknown"};
Martin Christoph Hierholzer
committed
if(pdata->network->getValueType() == typeid(int8_t)) { dataTypeName = "int8"; }
else if(pdata->network->getValueType() == typeid(uint8_t)) { dataTypeName = "uint8"; }
else if(pdata->network->getValueType() == typeid(int16_t)) { dataTypeName = "int16"; }
else if(pdata->network->getValueType() == typeid(uint16_t)) { dataTypeName = "uint16"; }
else if(pdata->network->getValueType() == typeid(int32_t)) { dataTypeName = "int32"; }
else if(pdata->network->getValueType() == typeid(uint32_t)) { dataTypeName = "uint32"; }
else if(pdata->network->getValueType() == typeid(float)) { dataTypeName = "float"; }
else if(pdata->network->getValueType() == typeid(double)) { dataTypeName = "double"; }
else if(pdata->network->getValueType() == typeid(std::string)) { dataTypeName = "string"; }
Martin Christoph Hierholzer
committed
xmlpp::Element *valueTypeElement = variable->add_child("value_type");
valueTypeElement->set_child_text(dataTypeName);
// add sub-element containing the data flow direction
std::string dataFlowName{"application_to_control_system"};
Martin Christoph Hierholzer
committed
if(pdata->network->getFeedingNode() == *this) { dataFlowName = "control_system_to_application"; }
Martin Christoph Hierholzer
committed
xmlpp::Element *directionElement = variable->add_child("direction");
directionElement->set_child_text(dataFlowName);
// add sub-element containing the engineering unit
xmlpp::Element *unitElement = variable->add_child("unit");
Martin Christoph Hierholzer
committed
unitElement->set_child_text(pdata->network->getUnit());
Martin Christoph Hierholzer
committed
}
/*********************************************************************************************************************/
bool VariableNetworkNode::operator==(const VariableNetworkNode& other) const {
Martin Christoph Hierholzer
committed
if(other.pdata != pdata) return false;
Martin Christoph Hierholzer
committed
return true;
}
/*********************************************************************************************************************/
bool VariableNetworkNode::operator!=(const VariableNetworkNode& other) const {
return !operator==(other);
}
Martin Christoph Hierholzer
committed
/*********************************************************************************************************************/
VariableNetworkNode& VariableNetworkNode::operator<<(const VariableNetworkNode &other) {
if(pdata->direction == VariableDirection::invalid) pdata->direction = VariableDirection::consuming;
if(other.pdata->direction == VariableDirection::invalid) other.pdata->direction = VariableDirection::feeding;
Application::getInstance().connect(*this, other);
return *this;
}
/*********************************************************************************************************************/
VariableNetworkNode& VariableNetworkNode::operator>>(const VariableNetworkNode &other) {
if(pdata->direction == VariableDirection::invalid) pdata->direction = VariableDirection::feeding;
if(other.pdata->direction == VariableDirection::invalid) other.pdata->direction = VariableDirection::consuming;
Application::getInstance().connect(*this, other);
return *this;
}
Martin Christoph Hierholzer
committed
/*********************************************************************************************************************/
VariableNetworkNode& VariableNetworkNode::operator[](const VariableNetworkNode &trigger) {
Martin Christoph Hierholzer
committed
if(pdata->direction == VariableDirection::invalid) pdata->direction = VariableDirection::feeding;
assert(pdata->direction == VariableDirection::feeding);
Martin Christoph Hierholzer
committed
// if this node is not yet part of a network, we have to add ourselves to a new network
if(pdata->network == nullptr) {
Martin Christoph Hierholzer
committed
Application::getInstance().createNetwork().addNode(*this);
Martin Christoph Hierholzer
committed
}
pdata->network->addTrigger(trigger);
return *this;
}