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)
Martin Christoph Hierholzer
committed
: pdata(new VariableNetworkNode_data)
Martin Christoph Hierholzer
committed
{
pdata->type = NodeType::Application;
pdata->mode = accessor.getUpdateMode();
pdata->direction = accessor.getDirection();
pdata->valueType = &(accessor.getValueType());
pdata->unit = accessor.getUnit();
pdata->appNode = &accessor;
pdata->nElements = accessor.getNumberOfElements();
pdata->description = accessor.getDescription();
Martin Christoph Hierholzer
committed
}
/*********************************************************************************************************************/
Martin Christoph Hierholzer
committed
VariableNetworkNode::VariableNetworkNode(const std::string &devAlias, const std::string ®Name, UpdateMode mod,
Martin Christoph Hierholzer
committed
VariableDirection dir, const std::type_info &valTyp, size_t nElements)
Martin Christoph Hierholzer
committed
: pdata(new VariableNetworkNode_data)
Martin Christoph Hierholzer
committed
{
pdata->type = NodeType::Device;
pdata->mode = mod;
pdata->direction = dir;
pdata->valueType = &valTyp;
pdata->deviceAlias = devAlias;
pdata->registerName = regName;
Martin Christoph Hierholzer
committed
pdata->nElements = nElements;
Martin Christoph Hierholzer
committed
}
Martin Christoph Hierholzer
committed
Martin Christoph Hierholzer
committed
/*********************************************************************************************************************/
Martin Christoph Hierholzer
committed
VariableNetworkNode::VariableNetworkNode(std::string pubName, VariableDirection dir, const std::type_info &valTyp,
size_t nElements)
Martin Christoph Hierholzer
committed
: pdata(new VariableNetworkNode_data)
Martin Christoph Hierholzer
committed
{
pdata->type = NodeType::ControlSystem;
pdata->mode = UpdateMode::push;
pdata->direction = dir;
pdata->valueType = &valTyp;
pdata->publicName = pubName;
Martin Christoph Hierholzer
committed
pdata->nElements = nElements;
Martin Christoph Hierholzer
committed
}
Martin Christoph Hierholzer
committed
/*********************************************************************************************************************/
VariableNetworkNode::VariableNetworkNode(VariableNetworkNode& nodeToTrigger, int)
Martin Christoph Hierholzer
committed
: pdata(new VariableNetworkNode_data)
Martin Christoph Hierholzer
committed
{
pdata->type = NodeType::TriggerReceiver;
pdata->direction = VariableDirection::consuming;
Martin Christoph Hierholzer
committed
pdata->triggerReceiver = nodeToTrigger;
Martin Christoph Hierholzer
committed
}
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 || pdata->type == NodeType::Constant;
Martin Christoph Hierholzer
committed
}
/*********************************************************************************************************************/
void VariableNetworkNode::dump() const {
Martin Christoph Hierholzer
committed
if(pdata->type == NodeType::Application) std::cout << " type = Application ('" << pdata->appNode->getName() << "')";
Martin Christoph Hierholzer
committed
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";
Martin Christoph Hierholzer
committed
if(pdata->type == NodeType::Constant) std::cout << " type = Constant";
Martin Christoph Hierholzer
committed
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 << " length: " << pdata->nElements;
Martin Christoph Hierholzer
committed
Martin Christoph Hierholzer
committed
std::cout << " [ptr: " << &(*pdata) << "]";
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
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
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());
// add sub-element containing the description
xmlpp::Element *descriptionElement = variable->add_child("description");
descriptionElement->set_child_text(pdata->network->getDescription());
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
/*********************************************************************************************************************/
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;
}
Martin Christoph Hierholzer
committed
/*********************************************************************************************************************/
VariableNetworkNode VariableNetworkNode::operator>>(VariableNetworkNode other) {
Martin Christoph Hierholzer
committed
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[](VariableNetworkNode trigger) {
// check if node already has a trigger
Martin Christoph Hierholzer
committed
if(pdata->externalTrigger.getType() != NodeType::invalid) {
throw ApplicationExceptionWithID<ApplicationExceptionID::illegalVariableNetwork>(
"Only one external trigger per variable network is allowed.");
}
Martin Christoph Hierholzer
committed
// force direction of the node we are operating on to be feeding
Martin Christoph Hierholzer
committed
if(pdata->direction == VariableDirection::invalid) pdata->direction = VariableDirection::feeding;
assert(pdata->direction == VariableDirection::feeding);
Martin Christoph Hierholzer
committed
// force direction of the triggering node to be feeding
if(trigger.pdata->direction == VariableDirection::invalid) trigger.pdata->direction = VariableDirection::feeding;
assert(trigger.pdata->direction == VariableDirection::feeding);
// create copy of the node
VariableNetworkNode nodeWithTrigger;
Martin Christoph Hierholzer
committed
nodeWithTrigger.pdata.reset(new VariableNetworkNode_data(*pdata));
// add ourselves as a trigger receiver to the other network
if(!trigger.hasOwner()) {
Application::getInstance().createNetwork().addNode(trigger);
Martin Christoph Hierholzer
committed
}
trigger.getOwner().addTriggerReceiver(nodeWithTrigger);
// set flag and store pointer to other network
Martin Christoph Hierholzer
committed
nodeWithTrigger.pdata->externalTrigger = trigger;
// return the new node
return nodeWithTrigger;
Martin Christoph Hierholzer
committed
}
Martin Christoph Hierholzer
committed
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
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
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
/*********************************************************************************************************************/
VariableNetworkNode::VariableNetworkNode() {}
/*********************************************************************************************************************/
void VariableNetworkNode::setValueType(const std::type_info& newType) const {
assert(*pdata->valueType == typeid(AnyType));
pdata->valueType = &newType;
}
/*********************************************************************************************************************/
bool VariableNetworkNode::hasExternalTrigger() const {
return pdata->externalTrigger.getType() != NodeType::invalid;
}
/*********************************************************************************************************************/
VariableNetworkNode VariableNetworkNode::getExternalTrigger() {
assert(pdata->externalTrigger.getType() != NodeType::invalid);
return pdata->externalTrigger;
}
/*********************************************************************************************************************/
bool VariableNetworkNode::hasOwner() const {
return pdata->network != nullptr;
}
/*********************************************************************************************************************/
NodeType VariableNetworkNode::getType() const {
if(!pdata) return NodeType::invalid;
return pdata->type;
}
/*********************************************************************************************************************/
UpdateMode VariableNetworkNode::getMode() const {
return pdata->mode;
}
/*********************************************************************************************************************/
VariableDirection VariableNetworkNode::getDirection() const {
return pdata->direction;
}
/*********************************************************************************************************************/
const std::type_info& VariableNetworkNode::getValueType() const {
return *(pdata->valueType);
}
/*********************************************************************************************************************/
const std::string& VariableNetworkNode::getUnit() const {
return pdata->unit;
}
/*********************************************************************************************************************/
const std::string& VariableNetworkNode::getDescription() const {
return pdata->description;
}
/*********************************************************************************************************************/
VariableNetwork& VariableNetworkNode::getOwner() const {
assert(pdata->network != nullptr);
return *(pdata->network);
}
/*********************************************************************************************************************/
AccessorBase& VariableNetworkNode::getAppAccessor() const {
assert(pdata->appNode != nullptr);
return *(pdata->appNode);
}
/*********************************************************************************************************************/
boost::shared_ptr<mtca4u::TransferElement> VariableNetworkNode::getConstAccessor() const {
return pdata->constNode;
}
/*********************************************************************************************************************/
VariableNetworkNode VariableNetworkNode::getTriggerReceiver() {
assert(pdata->triggerReceiver.getType() != NodeType::invalid);
return pdata->triggerReceiver;
}
/*********************************************************************************************************************/
const std::string& VariableNetworkNode::getPublicName() const {
assert(pdata->type == NodeType::ControlSystem);
return pdata->publicName;
}
/*********************************************************************************************************************/
const std::string& VariableNetworkNode::getDeviceAlias() const {
assert(pdata->type == NodeType::Device);
return pdata->deviceAlias;
}
/*********************************************************************************************************************/
const std::string& VariableNetworkNode::getRegisterName() const {
assert(pdata->type == NodeType::Device);
return pdata->registerName;
}
/*********************************************************************************************************************/
void VariableNetworkNode::setNumberOfElements(size_t nElements) {
pdata->nElements = nElements;
}
/*********************************************************************************************************************/
size_t VariableNetworkNode::getNumberOfElements() const {
return pdata->nElements;
}