Skip to content
Snippets Groups Projects
VariableNetwork.h 5.92 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>

#include "Flags.h"

namespace ChimeraTK {

  class AccessorBase;

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

    public:

      /** Define accessor types */
          Device, ControlSystem, Application, invalid
      /** Structure describing a node of the network */
      struct Node {
          UpdateMode mode{UpdateMode::invalid};

          /** Pointer to Accessor if type == Application */
          AccessorBase *appNode{nullptr};

          /** Public name if type == ControlSystem */
          std::string publicName;

          /** Device information if type == Device */
          std::string deviceAlias;
          std::string registerName;

          /** Function checking if the node requires a fixed implementation */
          bool hasImplementation() const {
            return type == NodeType::Device || type == NodeType::ControlSystem;
          }

          /** Print node information to std::cout */
          void dump() const {
            if(type == NodeType::Application) std::cout << " type = Application" << std::endl;
            if(type == NodeType::ControlSystem) std::cout << " type = ControlSystem ('" << publicName << "')" << std::endl;
            if(type == NodeType::Device) std::cout << " type = Device (" << deviceAlias << ": "
                << registerName << ")" << std::endl;
          }

          /** Compare two nodes */
          bool operator==(const Node& other) const {
            if(other.type != type) return false;
            if(other.mode != mode) return false;
            if(other.appNode != appNode) return false;
            if(other.publicName != publicName) return false;
            if(other.deviceAlias != deviceAlias) return false;
            if(other.registerName != registerName) return false;
            return true;
          }
          bool operator!=(const Node& other) const {
            return !operator==(other);
          }
      /** 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& 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 &deviceAlias,
          const std::string &registerName, UpdateMode mode);
      /** 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;
      }

      /** Return the feeding node */
      const Node& getFeedingNode() const { return feeder; }
      /** Return list of consuming nodes */
      const std::list<Node>& getConsumingNodes() const { return consumerList; }

      /** Dump the network structure to std::cout */
      void dump() 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);
      }

      /** Feeding node (i.e. the node providing values to the network) */
      Node feeder;
      /** List of consuming nodes (i.e. the nodes receiving values from the network) */
      std::list<Node> consumerList;

      /** 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)};

  };

} /* namespace ChimeraTK */

#endif /* CHIMERATK_VARIABLE_NETWORK_H */