Newer
Older
Martin Christoph Hierholzer
committed
/*
* VariableNetworkNode.h
*
* Created on: Jun 23, 2016
* Author: Martin Hierholzer
*/
#ifndef CHIMERATK_VARIABLE_NETWORK_NODE_H
#define CHIMERATK_VARIABLE_NETWORK_NODE_H
#include <unordered_map>
#include <unordered_set>
Martin Christoph Hierholzer
committed
Martin Christoph Hierholzer
committed
#include <assert.h>
Martin Christoph Hierholzer
committed
#include <boost/shared_ptr.hpp>
#include <ChimeraTK/NDRegisterAccessorAbstractor.h>
Martin Christoph Hierholzer
committed
Martin Christoph Hierholzer
committed
#include "ConstantAccessor.h"
#include "MetaDataPropagatingRegisterDecorator.h"
Martin Christoph Hierholzer
committed
namespace ChimeraTK {
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
class VariableNetwork;
class AccessorBase;
class EntityOwner;
struct VariableNetworkNode_data;
/** Pseudo type to identify nodes which can have arbitrary types */
class AnyType {};
/** Class describing a node of a variable network */
class VariableNetworkNode {
public:
/** Copy-constructor: Just copy the pointer to the data storage object */
VariableNetworkNode(const VariableNetworkNode& other);
/** Copy by assignment operator: Just copy the pointer to the data storage
* object */
VariableNetworkNode& operator=(const VariableNetworkNode& rightHandSide);
/** Constructor for an Application node */
VariableNetworkNode(EntityOwner* owner, ChimeraTK::TransferElementAbstractor* accessorBridge,
const std::string& name, VariableDirection direction, std::string unit, size_t nElements, UpdateMode mode,
const std::string& description, const std::type_info* valueType,
const std::unordered_set<std::string>& tags = {});
/** Constructor for a Device node */
VariableNetworkNode(const std::string& name, const std::string& deviceAlias, const std::string& registerName,
UpdateMode mode, VariableDirection direction, const std::type_info& valTyp = typeid(AnyType),
size_t nElements = 0);
/** Constructor for a ControlSystem node */
VariableNetworkNode(std::string publicName, VariableDirection direction,
const std::type_info& valTyp = typeid(AnyType), size_t nElements = 0);
/** Constructor for a TriggerReceiver node triggering the data transfer of
* another network. The additional dummy argument is only there to
* discriminate the signature from the copy constructor and will be ignored.
*/
VariableNetworkNode(VariableNetworkNode& nodeToTrigger, int);
/** Constructor to wrap a VariableNetworkNode_data pointer */
VariableNetworkNode(boost::shared_ptr<VariableNetworkNode_data> pdata);
/** Default constructor for an invalid node */
VariableNetworkNode();
/** Factory function for a constant (a constructor cannot be templated) */
template<typename UserType>
static VariableNetworkNode makeConstant(bool makeFeeder, UserType value = 0, size_t length = 1);
/** Change meta data (name, unit, description and optionally tags). This
* function may only be used on Application-type nodes. If the optional
* argument tags is omitted, the tags will not be changed. To clear the
* tags, an empty set can be passed. */
void setMetaData(const std::string& name, const std::string& unit, const std::string& description);
void setMetaData(const std::string& name, const std::string& unit, const std::string& description,
const std::unordered_set<std::string>& tags);
/** Set the owner network of this node. If an owner network is already set, an
* assertion will be raised */
void setOwner(VariableNetwork* network);
/** Clear the owner network of this node. */
void clearOwner();
/** Set the value type for this node. Only possible of the current value type
* is undecided (i.e. AnyType). */
void setValueType(const std::type_info& newType) const;
/** Set the direction for this node. Only possible if current direction is
* VariableDirection::feeding and the node type is NodeType::ControlSystem. */
void setDirection(VariableDirection newDirection) const;
/** Function checking if the node requires a fixed implementation */
bool hasImplementation() const;
/** Compare two nodes */
bool operator==(const VariableNetworkNode& other) const;
bool operator!=(const VariableNetworkNode& other) const;
bool operator<(const VariableNetworkNode& other) const;
/** Connect two nodes */
VariableNetworkNode operator>>(VariableNetworkNode other);
Martin Christoph Hierholzer
committed
/** Add a trigger */
VariableNetworkNode operator[](VariableNetworkNode trigger);
Martin Christoph Hierholzer
committed
/** Check for presence of an external trigger */
bool hasExternalTrigger() const;
/** Return the external trigger node. if no external trigger is present, an
* assertion will be raised. */
VariableNetworkNode getExternalTrigger();
Martin Christoph Hierholzer
committed
/** Print node information to std::cout */
void dump(std::ostream& stream = std::cout) const;
Martin Christoph Hierholzer
committed
/** Check if the node already has an owner */
bool hasOwner() const;
/** Add a tag. This function may only be used on Application-type nodes. Valid
* names for tags only contain
* alpha-numeric characters (i.e. no spaces and no special characters). @todo
* enforce this!*/
void addTag(const std::string& tag);
Martin Christoph Hierholzer
committed
/** Getter for the properties */
NodeType getType() const;
UpdateMode getMode() const;
VariableDirection getDirection() const;
const std::type_info& getValueType() const;
std::string getName() const;
std::string getQualifiedName() const;
const std::string& getUnit() const;
const std::string& getDescription() const;
VariableNetwork& getOwner() const;
VariableNetworkNode getNodeToTrigger();
const std::string& getPublicName() const;
const std::string& getDeviceAlias() const;
const std::string& getRegisterName() const;
const std::unordered_set<std::string>& getTags() const;
void setNumberOfElements(size_t nElements);
size_t getNumberOfElements() const;
ChimeraTK::TransferElementAbstractor& getAppAccessorNoType();
Martin Christoph Hierholzer
committed
void setPublicName(const std::string& name) const;
Martin Christoph Hierholzer
committed
template<typename UserType>
ChimeraTK::NDRegisterAccessorAbstractor<UserType>& getAppAccessor() const;
template<typename UserType>
void setAppAccessorImplementation(boost::shared_ptr<ChimeraTK::NDRegisterAccessor<UserType>> impl) const;
template<typename UserType>
boost::shared_ptr<ChimeraTK::NDRegisterAccessor<UserType>> getConstAccessor() const;
/** Return the unique ID of this node (will change every time the application
* is started). */
const void* getUniqueId() const { return pdata.get(); }
/** Change pointer to the accessor. May only be used for application nodes. */
void setAppAccessorPointer(ChimeraTK::TransferElementAbstractor* accessor);
Martin Christoph Hierholzer
committed
EntityOwner* getOwningModule() const;
void setOwningModule(EntityOwner* newOwner) const;
void accept(Visitor<VariableNetworkNode>& visitor) const;
// protected: @todo make protected again (with proper interface extension)
boost::shared_ptr<VariableNetworkNode_data> pdata;
};
/*********************************************************************************************************************/
/** We use a pimpl pattern so copied instances of VariableNetworkNode refer to
* the same instance of the data structure and thus stay consistent all the
* time. */
struct VariableNetworkNode_data {
VariableNetworkNode_data() {}
/** Type of the node (Application, Device, ControlSystem, Trigger) */
NodeType type{NodeType::invalid};
Martin Christoph Hierholzer
committed
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
/** Update mode: poll or push */
UpdateMode mode{UpdateMode::invalid};
/** Node direction: feeding or consuming */
VariableDirection direction{VariableDirection::invalid, false};
/** Value type of this node. If the type_info is the typeid of AnyType, the
* actual type can be decided when making the connections. */
const std::type_info* valueType{&typeid(AnyType)};
/** Engineering unit. If equal to ChimeraTK::TransferElement::unitNotSet, no
* unit has been defined (and any unit is allowed). */
std::string unit{ChimeraTK::TransferElement::unitNotSet};
/** Description */
std::string description{""};
/** The network this node belongs to */
VariableNetwork* network{nullptr};
/** Pointer to implementation if type == Constant */
boost::shared_ptr<ChimeraTK::TransferElement> constNode;
/** Pointer to implementation if type == Application */
ChimeraTK::TransferElementAbstractor* appNode{nullptr};
/** Pointer to network which should be triggered by this node */
VariableNetworkNode nodeToTrigger{nullptr};
/** Pointer to the network providing the external trigger. May only be used
* for feeding nodes with an update mode poll. When enabled, the update mode
* will be converted into push. */
VariableNetworkNode externalTrigger{nullptr};
/** Public name if type == ControlSystem */
std::string publicName;
/** Accessor name if type == Application */
std::string name;
std::string qualifiedName;
/** Device information if type == Device */
std::string deviceAlias;
std::string registerName;
/** Number of elements in the variable. 0 means not yet decided. */
size_t nElements{0};
Martin Christoph Hierholzer
committed
/** Set of tags if type == Application */
std::unordered_set<std::string> tags;
Martin Christoph Hierholzer
committed
/** Map to store triggered versions of this node. The map key is the trigger
* node and the value is the node with the respective trigger added. */
std::map<VariableNetworkNode, VariableNetworkNode> nodeWithTrigger;
Martin Christoph Hierholzer
committed
/** Pointer to the module owning this node */
EntityOwner* owningModule{nullptr};
};
Martin Christoph Hierholzer
committed
251
252
253
254
255
256
257
258
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
/*********************************************************************************************************************/
/*** Implementations
* *************************************************************************************************/
/*********************************************************************************************************************/
template<typename UserType>
VariableNetworkNode VariableNetworkNode::makeConstant(bool makeFeeder, UserType value, size_t length) {
VariableNetworkNode node;
node.pdata = boost::make_shared<VariableNetworkNode_data>();
node.pdata->constNode.reset(new ConstantAccessor<UserType>(value, length));
node.pdata->type = NodeType::Constant;
node.pdata->valueType = &typeid(UserType);
node.pdata->nElements = length;
node.pdata->name = "*UNNAMED CONSTANT*";
if(makeFeeder) {
node.pdata->direction = {VariableDirection::feeding, false};
node.pdata->mode = UpdateMode::push;
}
else {
node.pdata->direction = {VariableDirection::consuming, false};
node.pdata->mode = UpdateMode::poll;
}
return node;
}
/*********************************************************************************************************************/
template<typename UserType>
ChimeraTK::NDRegisterAccessorAbstractor<UserType>& VariableNetworkNode::getAppAccessor() const {
assert(typeid(UserType) == getValueType());
assert(pdata->type == NodeType::Application);
auto accessor = static_cast<ChimeraTK::NDRegisterAccessorAbstractor<UserType>*>(pdata->appNode);
assert(accessor != nullptr);
return *accessor;
}
/*********************************************************************************************************************/
template<typename UserType>
boost::shared_ptr<ChimeraTK::NDRegisterAccessor<UserType>> VariableNetworkNode::getConstAccessor() const {
return boost::dynamic_pointer_cast<ChimeraTK::NDRegisterAccessor<UserType>>(pdata->constNode);
}
/*********************************************************************************************************************/
template<typename UserType>
void VariableNetworkNode::setAppAccessorImplementation(boost::shared_ptr<NDRegisterAccessor<UserType>> impl) const {
auto decorated = boost::make_shared<MetaDataPropagatingRegisterDecorator<UserType>>(impl, getOwningModule());
getAppAccessor<UserType>().replace(decorated);
Martin Christoph Hierholzer
committed
}
Martin Christoph Hierholzer
committed
} /* namespace ChimeraTK */
#endif /* CHIMERATK_VARIABLE_NETWORK_NODE_H */