Skip to content
Snippets Groups Projects
VariableNetwork.h 7.24 KiB
Newer Older
/*
 * VariableNetwork.h
 *
 *  Created on: Jun 14, 2016
 *      Author: Martin Hierholzer
 */

#ifndef CHIMERATK_VARIABLE_NETWORK_H
#define CHIMERATK_VARIABLE_NETWORK_H

#include <list>
#include <string>
#include <typeinfo>
#include <boost/mpl/for_each.hpp>

namespace ChimeraTK {

  class AccessorBase;

  /** This class describes a network of variables all connected to each other. */
  class VariableNetwork {

      VariableNetwork( const VariableNetwork& other ) = delete;         // non construction-copyable
      VariableNetwork& operator=( const VariableNetwork& ) = delete;    // non copyable

      /** Define trigger types. The trigger decides when values are fed into the network and distributed to the consumers. */
      enum class TriggerType {
          feeder,           ///< The feeder has an UpdateMode::push and thus decides when new values are fed
          pollingConsumer,  ///< If there is exacly one consumer with UpdateMode::poll, it will trigger the feeding
          external,         ///< another variable network can trigger the feeding of this network
          none              ///< no trigger has yet been selected
      /** Add an application-side node (i.e. an Accessor) to the network. */
      void addAppNode(AccessorBase &a);

      /** Add control-system-to-device publication. The given accessor will be used to derive the requred value type.
       *  The name will be the name of the process variable visible in the control system adapter. */
      void addFeedingPublication(AccessorBase &a, const std::string& name);
      /** Add control-system-to-device publication. The given accessor will be used to derive the requred value type.
       *  The name will be the name of the process variable visible in the control system adapter. */
      void addFeedingPublication(const std::type_info &typeInfo, const std::string& unit, const std::string& name);
      /** Add device-to-control-system publication. */
      void addConsumingPublication(const std::string& name);
      /** Add a device register as a consuming node (i.e. which will be written by this network) */
      void addConsumingDeviceRegister(const std::string &deviceAlias, const std::string &registerName);
      /** Add a device register as a feeding node (i.e. which will be read from this network) */
      void addFeedingDeviceRegister(AccessorBase &a, const std::string &deviceAlias, const std::string &registerName,
          UpdateMode mode);

      /** Add a device register as a feeding node (i.e. which will be read from this network) */
      void addFeedingDeviceRegister(const std::type_info &typeInfo, const std::string& unit,
          const std::string &deviceAlias, const std::string &registerName, UpdateMode mode);
      /** Add a trigger receiver node */
      void addTriggerReceiver(VariableNetwork *network);

      /** Check if the network already has a feeding node connected to it. */
      bool hasFeedingNode() const;
      /** Count the number of consuming nodes in the network */
      size_t countConsumingNodes() const;

      /** Count the number of nodes requiring a fixed implementation */
      size_t countFixedImplementations() const;

      /** Check if either of the given accessors is part of this network. If the second argument is omitted, only
       *  the first accessor will be checked. */
      bool hasAppNode(AccessorBase *a, AccessorBase *b=nullptr) const;

      /** Obtain the type info of the UserType. If the network type has not yet been determined (i.e. if no output
       *  accessor has been assigned yet), the typeid of void will be returned. */
      const std::type_info& getValueType() const {
        return *valueType;
      }

      const VariableNetworkNode& getFeedingNode() const { return feeder; }
      const std::list<VariableNetworkNode>& getConsumingNodes() const { return consumerList; }
      /** Dump the network structure to std::cout. The optional linePrefix will be prepended to all lines. */
      void dump(const std::string& linePrefix="") const;
      /** Compare two networks */
      bool operator==(const VariableNetwork &other) const {
        if(other.feeder != feeder) return false;
        if(other.valueType != valueType) return false;
        if(other.consumerList != consumerList) return false;
        return true;
      }
      bool operator!=(const VariableNetwork &other) const {
        return !operator==(other);
      }

      /** Return the trigger type. This function will also do some checking if the network confguration is valid under
       *  the aspect of the trigger type. */
      /** Return the enginerring unit */
      const std::string& getUnit() { return engineeringUnit; }

      /** Return the network providing the external trigger to this network, if TriggerType::external. If the network
       *  has another trigger type, an exception will be thrown. */
      VariableNetwork& getExternalTrigger();

      /** Add an accessor belonging to another network as an external trigger to this network. Whenever the
       *  VariableNetwork of the given accessor will be fed with a new value, feeding of this network will be
       *  triggered as well. */
      void addTrigger(AccessorBase &trigger);

      /** Check if the network is legally configured */
      void check();

      /** Check the flag if the network connections has been created already */
      bool isCreated() const { return flagIsCreated; }

      /** Set the flag that the network connections are created */
      void markCreated() { flagIsCreated = true; }

      /** Assign a ProcessVariable as implementation for the external trigger */
      void setExternalTriggerImpl(boost::shared_ptr< mtca4u::ProcessVariable > impl) {
        externalTriggerImpl = impl;
      }

      /** */
      boost::shared_ptr< mtca4u::ProcessVariable > getExternalTriggerImpl() const {
        return externalTriggerImpl;
      }

      /** Feeding node (i.e. the node providing values to the network) */
      /** List of consuming nodes (i.e. the nodes receiving values from the network) */

      /** The network value type id. Since in C++, std::type_info is non-copyable and typeid() returns a reference to
       *  an object with static storage duration, we have to (and can safely) store a pointer here. */
      const std::type_info* valueType{&typeid(void)};

      /** Flag if an external trigger has been added to this network */
      bool hasExternalTrigger{false};

      /** Pointer to the network providing the external trigger */
      VariableNetwork *externalTrigger{nullptr};

      /** Pointer to ProcessVariable providing the trigger (if external trigger is enabled) */
      boost::shared_ptr< mtca4u::ProcessVariable > externalTriggerImpl;

      /** Flag if the network connections have been created already */
      bool flagIsCreated{false};

  };

} /* namespace ChimeraTK */

#endif /* CHIMERATK_VARIABLE_NETWORK_H */