/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * Copyright 2017 (c) Fraunhofer IOSB (Author: Julius Pfrommer) * Copyright 2017 (c) Julian Grothoff * Copyright 2017 (c) Stefan Profanter, fortiss GmbH */ #ifndef UA_SERVER_NODES_H_ #define UA_SERVER_NODES_H_ /* !!! Warning !!! * * If you are not developing a nodestore plugin, then you should not work with * the definitions from this file directly. The underlying node structures are * not meant to be used directly by end users. Please use the public server API * / OPC UA services to interact with the information model. */ #ifdef __cplusplus extern "C" { #endif #include "ua_server.h" /** * .. _information-modelling: * * Information Modelling * ===================== * * Information modelling in OPC UA combines concepts from object-orientation and * semantic modelling. At the core, an OPC UA information model is a graph made * up of * * - Nodes: There are eight possible Node types (variable, object, method, ...) * - References: Typed and directed relations between two nodes * * Every node is identified by a unique (within the server) :ref:`nodeid`. * Reference are triples of the form ``(source-nodeid, referencetype-nodeid, * target-nodeid)``. An example reference between nodes is a * ``hasTypeDefinition`` reference between a Variable and its VariableType. Some * ReferenceTypes are *hierarchic* and must not form *directed loops*. See the * section on :ref:`ReferenceTypes ` for more details on * possible references and their semantics. * * **Warning!!** The structures defined in this section are only relevant for * the developers of custom Nodestores. The interaction with the information * model is possible only via the OPC UA :ref:`services`. So the following * sections are purely informational so that users may have a clear mental * model of the underlying representation. * * Base Node Attributes * -------------------- * * Nodes contain attributes according to their node type. The base node * attributes are common to all node types. In the OPC UA :ref:`services`, * attributes are referred to via the :ref:`nodeid` of the containing node and * an integer :ref:`attribute-id`. * * Internally, open62541 uses ``UA_Node`` in places where the exact node type is * not known or not important. The ``nodeClass`` attribute is used to ensure the * correctness of casting from ``UA_Node`` to a specific node type. */ /* List of reference targets with the same reference type and direction */ typedef struct { UA_NodeId referenceTypeId; UA_Boolean isInverse; size_t targetIdsSize; UA_ExpandedNodeId *targetIds; } UA_NodeReferenceKind; #define UA_NODE_BASEATTRIBUTES \ UA_NodeId nodeId; \ UA_NodeClass nodeClass; \ UA_QualifiedName browseName; \ UA_LocalizedText displayName; \ UA_LocalizedText description; \ UA_UInt32 writeMask; \ size_t referencesSize; \ UA_NodeReferenceKind *references; \ \ /* Members specific to open62541 */ \ void *context; typedef struct { UA_NODE_BASEATTRIBUTES } UA_Node; /** * VariableNode * ------------ * * Variables store values in a :ref:`datavalue` together with * metadata for introspection. Most notably, the attributes data type, value * rank and array dimensions constrain the possible values the variable can take * on. * * Variables come in two flavours: properties and datavariables. Properties are * related to a parent with a ``hasProperty`` reference and may not have child * nodes themselves. Datavariables may contain properties (``hasProperty``) and * also datavariables (``hasComponents``). * * All variables are instances of some :ref:`variabletypenode` in return * constraining the possible data type, value rank and array dimensions * attributes. * * Data Type * ^^^^^^^^^ * * The (scalar) data type of the variable is constrained to be of a specific * type or one of its children in the type hierarchy. The data type is given as * a NodeId pointing to a :ref:`datatypenode` in the type hierarchy. See the * Section :ref:`datatypenode` for more details. * * If the data type attribute points to ``UInt32``, then the value attribute * must be of that exact type since ``UInt32`` does not have children in the * type hierarchy. If the data type attribute points ``Number``, then the type * of the value attribute may still be ``UInt32``, but also ``Float`` or * ``Byte``. * * Consistency between the data type attribute in the variable and its * :ref:`VariableTypeNode` is ensured. * * Value Rank * ^^^^^^^^^^ * * This attribute indicates whether the value attribute of the variable is an * array and how many dimensions the array has. It may have the following * values: * * - ``n >= 1``: the value is an array with the specified number of dimensions * - ``n = 0``: the value is an array with one or more dimensions * - ``n = -1``: the value is a scalar * - ``n = -2``: the value can be a scalar or an array with any number of dimensions * - ``n = -3``: the value can be a scalar or a one dimensional array * * Consistency between the value rank attribute in the variable and its * :ref:`variabletypenode` is ensured. * * Array Dimensions * ^^^^^^^^^^^^^^^^ * * If the value rank permits the value to be a (multi-dimensional) array, the * exact length in each dimensions can be further constrained with this * attribute. * * - For positive lengths, the variable value is guaranteed to be of the same * length in this dimension. * - The dimension length zero is a wildcard and the actual value may have any * length in this dimension. * * Consistency between the array dimensions attribute in the variable and its * :ref:`variabletypenode` is ensured. */ /* Indicates whether a variable contains data inline or whether it points to an * external data source */ typedef enum { UA_VALUESOURCE_DATA, UA_VALUESOURCE_DATASOURCE } UA_ValueSource; #define UA_NODE_VARIABLEATTRIBUTES \ /* Constraints on possible values */ \ UA_NodeId dataType; \ UA_Int32 valueRank; \ size_t arrayDimensionsSize; \ UA_UInt32 *arrayDimensions; \ \ /* The current value */ \ UA_ValueSource valueSource; \ union { \ struct { \ UA_DataValue value; \ UA_ValueCallback callback; \ } data; \ UA_DataSource dataSource; \ } value; typedef struct { UA_NODE_BASEATTRIBUTES UA_NODE_VARIABLEATTRIBUTES UA_Byte accessLevel; UA_Double minimumSamplingInterval; UA_Boolean historizing; /* currently unsupported */ } UA_VariableNode; /** * .. _variabletypenode: * * VariableTypeNode * ---------------- * * VariableTypes are used to provide type definitions for variables. * VariableTypes constrain the data type, value rank and array dimensions * attributes of variable instances. Furthermore, instantiating from a specific * variable type may provide semantic information. For example, an instance from * ``MotorTemperatureVariableType`` is more meaningful than a float variable * instantiated from ``BaseDataVariable``. */ typedef struct { UA_NODE_BASEATTRIBUTES UA_NODE_VARIABLEATTRIBUTES UA_Boolean isAbstract; /* Members specific to open62541 */ UA_NodeTypeLifecycle lifecycle; } UA_VariableTypeNode; /** * .. _methodnode: * * MethodNode * ---------- * * Methods define callable functions and are invoked using the :ref:`Call * ` service. MethodNodes may have special properties (variable * childen with a ``hasProperty`` reference) with the :ref:`qualifiedname` ``(0, * "InputArguments")`` and ``(0, "OutputArguments")``. The input and output * arguments are both described via an array of ``UA_Argument``. While the Call * service uses a generic array of :ref:`variant` for input and output, the * actual argument values are checked to match the signature of the MethodNode. * * Note that the same MethodNode may be referenced from several objects (and * object types). For this, the NodeId of the method *and of the object * providing context* is part of a Call request message. */ typedef struct { UA_NODE_BASEATTRIBUTES UA_Boolean executable; /* Members specific to open62541 */ UA_MethodCallback method; } UA_MethodNode; /** * ObjectNode * ---------- * * Objects are used to represent systems, system components, real-world objects * and software objects. Objects are instances of an :ref:`object * type` and may contain variables, methods and further * objects. */ typedef struct { UA_NODE_BASEATTRIBUTES UA_Byte eventNotifier; } UA_ObjectNode; /** * .. _objecttypenode: * * ObjectTypeNode * -------------- * * ObjectTypes provide definitions for Objects. Abstract objects cannot be * instantiated. See :ref:`node-lifecycle` for the use of constructor and * destructor callbacks. */ typedef struct { UA_NODE_BASEATTRIBUTES UA_Boolean isAbstract; /* Members specific to open62541 */ UA_NodeTypeLifecycle lifecycle; } UA_ObjectTypeNode; /** * .. _referencetypenode: * * ReferenceTypeNode * ----------------- * * Each reference between two nodes is typed with a ReferenceType that gives * meaning to the relation. The OPC UA standard defines a set of ReferenceTypes * as a mandatory part of OPC UA information models. * * - Abstract ReferenceTypes cannot be used in actual references and are only * used to structure the ReferenceTypes hierarchy * - Symmetric references have the same meaning from the perspective of the * source and target node * * The figure below shows the hierarchy of the standard ReferenceTypes (arrows * indicate a ``hasSubType`` relation). Refer to Part 3 of the OPC UA * specification for the full semantics of each ReferenceType. * * .. graphviz:: * * digraph tree { * * node [height=0, shape=box, fillcolor="#E5E5E5", concentrate=true] * * references [label="References\n(Abstract, Symmetric)"] * hierarchical_references [label="HierarchicalReferences\n(Abstract)"] * references -> hierarchical_references * * nonhierarchical_references [label="NonHierarchicalReferences\n(Abstract, Symmetric)"] * references -> nonhierarchical_references * * haschild [label="HasChild\n(Abstract)"] * hierarchical_references -> haschild * * aggregates [label="Aggregates\n(Abstract)"] * haschild -> aggregates * * organizes [label="Organizes"] * hierarchical_references -> organizes * * hascomponent [label="HasComponent"] * aggregates -> hascomponent * * hasorderedcomponent [label="HasOrderedComponent"] * hascomponent -> hasorderedcomponent * * hasproperty [label="HasProperty"] * aggregates -> hasproperty * * hassubtype [label="HasSubtype"] * haschild -> hassubtype * * hasmodellingrule [label="HasModellingRule"] * nonhierarchical_references -> hasmodellingrule * * hastypedefinition [label="HasTypeDefinition"] * nonhierarchical_references -> hastypedefinition * * hasencoding [label="HasEncoding"] * nonhierarchical_references -> hasencoding * * hasdescription [label="HasDescription"] * nonhierarchical_references -> hasdescription * * haseventsource [label="HasEventSource"] * hierarchical_references -> haseventsource * * hasnotifier [label="HasNotifier"] * hierarchical_references -> hasnotifier * * generatesevent [label="GeneratesEvent"] * nonhierarchical_references -> generatesevent * * alwaysgeneratesevent [label="AlwaysGeneratesEvent"] * generatesevent -> alwaysgeneratesevent * * {rank=same hierarchical_references nonhierarchical_references} * {rank=same generatesevent haseventsource hasmodellingrule * hasencoding hassubtype} * {rank=same alwaysgeneratesevent hasproperty} * * } * * The ReferenceType hierarchy can be extended with user-defined ReferenceTypes. * Many Companion Specifications for OPC UA define new ReferenceTypes to be used * in their domain of interest. * * For the following example of custom ReferenceTypes, we attempt to model the * structure of a technical system. For this, we introduce two custom * ReferenceTypes. First, the hierarchical ``contains`` ReferenceType indicates * that a system (represented by an OPC UA object) contains a component (or * subsystem). This gives rise to a tree-structure of containment relations. For * example, the motor (object) is contained in the car and the crankshaft is * contained in the motor. Second, the symmetric ``connectedTo`` ReferenceType * indicates that two components are connected. For example, the motor's * crankshaft is connected to the gear box. Connections are independent of the * containment hierarchy and can induce a general graph-structure. Further * subtypes of ``connectedTo`` could be used to differentiate between physical, * electrical and information related connections. A client can then learn the * layout of a (physical) system represented in an OPC UA information model * based on a common understanding of just two custom reference types. */ typedef struct { UA_NODE_BASEATTRIBUTES UA_Boolean isAbstract; UA_Boolean symmetric; UA_LocalizedText inverseName; } UA_ReferenceTypeNode; /** * .. _datatypenode: * * DataTypeNode * ------------ * * DataTypes represent simple and structured data types. DataTypes may contain * arrays. But they always describe the structure of a single instance. In * open62541, DataTypeNodes in the information model hierarchy are matched to * ``UA_DataType`` type descriptions for :ref:`generic-types` via their NodeId. * * Abstract DataTypes (e.g. ``Number``) cannot be the type of actual values. * They are used to constrain values to possible child DataTypes (e.g. * ``UInt32``). */ typedef struct { UA_NODE_BASEATTRIBUTES UA_Boolean isAbstract; } UA_DataTypeNode; /** * ViewNode * -------- * * Each View defines a subset of the Nodes in the AddressSpace. Views can be * used when browsing an information model to focus on a subset of nodes and * references only. ViewNodes can be created and be interacted with. But their * use in the :ref:`Browse` service is currently unsupported in * open62541. */ typedef struct { UA_NODE_BASEATTRIBUTES UA_Byte eventNotifier; UA_Boolean containsNoLoops; } UA_ViewNode; /** * Nodestore Plugin API * -------------------- * The following definitions are used for implementing custom node storage * backends. **Most users will want to use the default nodestore and don't need * to work with the nodestore API**. * * Outside of custom nodestore implementations, users should not manually edit * nodes. Please use the OPC UA services for that. Otherwise, all consistency * checks are omitted. This can crash the application eventually. */ typedef void (*UA_NodestoreVisitor)(void *visitorContext, const UA_Node *node); typedef struct { /* Nodestore context and lifecycle */ void *context; void (*deleteNodestore)(void *nodestoreContext); /* For non-multithreaded access, some nodestores allow that nodes are edited * without a copy/replace. This is not possible when the node is only an * intermediate representation and stored e.g. in a database backend. */ UA_Boolean inPlaceEditAllowed; /* The following definitions are used to create empty nodes of the different * node types. The memory is managed by the nodestore. Therefore, the node * has to be removed via a special deleteNode function. (If the new node is * not added to the nodestore.) */ UA_Node * (*newNode)(void *nodestoreContext, UA_NodeClass nodeClass); void (*deleteNode)(void *nodestoreContext, UA_Node *node); /* ``Get`` returns a pointer to an immutable node. ``Release`` indicates * that the pointer is no longer accessed afterwards. */ const UA_Node * (*getNode)(void *nodestoreContext, const UA_NodeId *nodeId); void (*releaseNode)(void *nodestoreContext, const UA_Node *node); /* Returns an editable copy of a node (needs to be deleted with the * deleteNode function or inserted / replaced into the nodestore). */ UA_StatusCode (*getNodeCopy)(void *nodestoreContext, const UA_NodeId *nodeId, UA_Node **outNode); /* Inserts a new node into the nodestore. If the NodeId is zero, then a * fresh numeric NodeId is assigned. If insertion fails, the node is * deleted. */ UA_StatusCode (*insertNode)(void *nodestoreContext, UA_Node *node, UA_NodeId *addedNodeId); /* To replace a node, get an editable copy of the node, edit and replace * with this function. If the node was already replaced since the copy was * made, UA_STATUSCODE_BADINTERNALERROR is returned. If the NodeId is not * found, UA_STATUSCODE_BADNODEIDUNKNOWN is returned. In both error cases, * the editable node is deleted. */ UA_StatusCode (*replaceNode)(void *nodestoreContext, UA_Node *node); /* Removes a node from the nodestore. */ UA_StatusCode (*removeNode)(void *nodestoreContext, const UA_NodeId *nodeId); /* Execute a callback for every node in the nodestore. */ void (*iterate)(void *nodestoreContext, void* visitorContext, UA_NodestoreVisitor visitor); } UA_Nodestore; /** * The following methods specialize internally for the different node classes * (distinguished by the nodeClass member) */ /* Attributes must be of a matching type (VariableAttributes, ObjectAttributes, * and so on). The attributes are copied. Note that the attributes structs do * not contain NodeId, NodeClass and BrowseName. The NodeClass of the node needs * to be correctly set before calling this method. UA_Node_deleteMembers is * called on the node when an error occurs internally. */ UA_StatusCode UA_EXPORT UA_Node_setAttributes(UA_Node *node, const void *attributes, const UA_DataType *attributeType); /* Reset the destination node and copy the content of the source */ UA_StatusCode UA_EXPORT UA_Node_copy(const UA_Node *src, UA_Node *dst); /* Allocate new node and copy the values from src */ UA_EXPORT UA_Node * UA_Node_copy_alloc(const UA_Node *src); /* Add a single reference to the node */ UA_StatusCode UA_EXPORT UA_Node_addReference(UA_Node *node, const UA_AddReferencesItem *item); /* Delete a single reference from the node */ UA_StatusCode UA_EXPORT UA_Node_deleteReference(UA_Node *node, const UA_DeleteReferencesItem *item); /* Delete all references of the node */ void UA_EXPORT UA_Node_deleteReferences(UA_Node *node); /* Remove all malloc'ed members of the node */ void UA_EXPORT UA_Node_deleteMembers(UA_Node *node); #ifdef __cplusplus } // extern "C" #endif #endif /* UA_SERVER_NODES_H_ */