Skip to content
Snippets Groups Projects
VariableNetworkNode.cc 5.54 KiB
Newer Older
/*
 * 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 {

  /*********************************************************************************************************************/

  bool VariableNetworkNode::hasImplementation() const {
    return type == NodeType::Device || type == NodeType::ControlSystem;
  }

  /*********************************************************************************************************************/

  void VariableNetworkNode::dump() const {
    if(type == NodeType::Application) std::cout << " type = Application";
    if(type == NodeType::ControlSystem) std::cout << " type = ControlSystem ('" << publicName << "')";
    if(type == NodeType::Device) std::cout << " type = Device (" << deviceAlias << ": " << registerName << ")";
    if(type == NodeType::TriggerReceiver) std::cout << " type = TriggerReceiver";
    if(type == NodeType::invalid) std::cout << " type = **invalid**";

    if(mode == UpdateMode::push) std::cout << " pushing" << std::endl;
    if(mode == UpdateMode::poll) std::cout << " polling" << std::endl;
}

  /*********************************************************************************************************************/

  void VariableNetworkNode::createXML(xmlpp::Element *rootElement) const {
    if(type != NodeType::ControlSystem) return;

    // 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
    mtca4u::RegisterPath directory(publicName);
    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");
    mtca4u::RegisterPath pathName(publicName);
    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"};
    if(network->getValueType() == typeid(int8_t)) { dataTypeName = "int8"; }
    else if(network->getValueType() == typeid(uint8_t)) { dataTypeName = "uint8"; }
    else if(network->getValueType() == typeid(int16_t)) { dataTypeName = "int16"; }
    else if(network->getValueType() == typeid(uint16_t)) { dataTypeName = "uint16"; }
    else if(network->getValueType() == typeid(int32_t)) { dataTypeName = "int32"; }
    else if(network->getValueType() == typeid(uint32_t)) { dataTypeName = "uint32"; }
    else if(network->getValueType() == typeid(float)) { dataTypeName = "float"; }
    else if(network->getValueType() == typeid(double)) { dataTypeName = "double"; }
    else if(network->getValueType() == typeid(std::string)) { dataTypeName = "string"; }
    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"};
    if(network->getFeedingNode() == *this) { dataFlowName = "control_system_to_application"; }
    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");
    unitElement->set_child_text(network->getUnit());
  }

  /*********************************************************************************************************************/

  bool VariableNetworkNode::operator==(const VariableNetworkNode& other) const {
    if(other.network != network) return false;
    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 VariableNetworkNode::operator!=(const VariableNetworkNode& other) const {
    return !operator==(other);
  }

}