/* * Accessor.h * * Created on: Jun 09, 2016 * Author: Martin Hierholzer */ #ifndef CHIMERATK_ACCESSOR_H #define CHIMERATK_ACCESSOR_H #include <string> #include <atomic> #include <mtca4u/RegisterPath.h> #include "Flags.h" #include "Application.h" #include "ApplicationModule.h" namespace ChimeraTK { using namespace mtca4u; class Application; /*********************************************************************************************************************/ // stupid temporary base class for accessors, which is not templated @todo TODO replace with proper class structure class AccessorBase { public: virtual ~AccessorBase() {} /** Return if the accessor is properly initialised. It is initialised if it was constructed passing the pointer * to an implementation (a NDRegisterAccessor), it is not initialised if it was constructed only using the * placeholder constructor without arguments. */ virtual bool isInitialised() const = 0; /** Use a ProcessVariable as implementation. */ virtual void useProcessVariable(const boost::shared_ptr<TransferElement> &var) = 0; /* Obtain the type info of the UserType */ virtual const std::type_info& getValueType() const = 0; /** Obtain direction of the accessor */ virtual VariableDirection getDirection() const = 0; /** Obtain the update mode of the accessor */ virtual UpdateMode getUpdateMode() const = 0; /* Obtain the unit of the variable */ virtual const std::string& getUnit() const = 0; /* Obtain the description of the variable */ virtual const std::string& getDescription() const = 0; /* Obtain the name of the accessor */ virtual const std::string& getName() const = 0; /** Read an input variable. In case of an output variable, an exception will be thrown. This function will block * the calling thread until the variable has been read. If the UpdateMode::push flag has been set when creating * the accessor, this function will wait until a new value has been provided to the variable. If a new value is * already available before calling this function, the function will be non-blocking and lock-free. */ virtual void read() = 0; /** Non-blocking read. Will return whether a new value was obtained. For pull-type varibales, always true is * returned, independently whether the value was changed or not. */ virtual bool readNonBlocking() = 0; /** Write an output variable. In case of an input variable, an exception will be thrown. */ virtual void write() = 0; /** Return number of elements in the variable (array size, or 1 for scalars) * @todo TODO FIXME This function is not needed like this. It is only used during the setup phase while making * the connections. There we should instead just obtain the number of elements from the VariableNetworkNode. * Like this, this function might easily be confused with the getNElements() function! */ virtual size_t getNumberOfElements() const = 0; /** Convert into VariableNetworkNode */ operator const VariableNetworkNode&() const { return node; } operator VariableNetworkNode&() { return node; } /** Return the implementation as a TransferElement */ virtual boost::shared_ptr<TransferElement> getTransferElement() = 0; /** Explicitly return the node */ VariableNetworkNode& getNode() { return node; } /** Connect with another node */ VariableNetworkNode operator>>(VariableNetworkNode other) { return node.operator>>(other); } protected: VariableNetworkNode node; friend class ApplicationModule; }; /*********************************************************************************************************************/ template< typename UserType > class Accessor : public AccessorBase { public: Accessor(Module *owner, const std::string &name, VariableDirection direction, std::string unit, size_t nElements, UpdateMode mode, const std::string &description) : _owner(owner), _name(name), _direction(direction), _unit(unit), _mode(mode), _description(description), _nElements{nElements} { _owner->registerAccessor(this); node = VariableNetworkNode(*this); } /** The default constructor takes no arguments and leaves the accessor uninitialised. It will be dysfunctional * until it is properly initialised using connectTo(). */ Accessor() : _owner(nullptr), _name("dysfunctional"), _direction(VariableDirection::invalid), _unit("invalid"), _mode(UpdateMode::invalid), _description("dysfunctional accessor"), _nElements{0} {} /** The destructor unregisters the accessor from the owner module */ ~Accessor() { _owner->unregisterAccessor(this); } VariableDirection getDirection() const {return _direction;} UpdateMode getUpdateMode() const {return _mode;} const std::string& getUnit() const {return _unit;} const std::string& getDescription() const {return _description;} const std::string& getName() const {return _name;} const std::type_info& getValueType() const { return typeid(UserType); } size_t getNumberOfElements() const { return _nElements; } /** Assign a new accessor to this accessor. */ void replace(const Accessor<UserType> &newAccessor) { _owner = newAccessor._owner; _name = newAccessor._name; _direction = newAccessor._direction; _unit = newAccessor._unit; _mode = newAccessor._mode; _description = newAccessor._description; _nElements = newAccessor._nElements; impl = newAccessor.impl; _owner->registerAccessor(this); node = VariableNetworkNode(*this); } boost::shared_ptr<TransferElement> getTransferElement() override { return boost::static_pointer_cast<TransferElement>(impl); } protected: Module *_owner; std::string _name; VariableDirection _direction; std::string _unit; UpdateMode _mode; std::string _description; size_t _nElements; boost::shared_ptr< NDRegisterAccessor<UserType> > impl; private: /** prevent copying by operator=, since it will be confusing (operator= may also be overloaded to access the * content of the buffer!) */ const Accessor<UserType>& operator=(const Accessor<UserType>& rightHandSide) const; }; } /* namespace ChimeraTK */ #endif /* CHIMERATK_ACCESSOR_H */