/// <summary> /// Creates a new object type. /// </summary> private BaseObjectTypeState CreateObjectType(NodeState parent, IDictionary <NodeId, IList <IReference> > externalReferences, string path, string name) { BaseObjectTypeState type = new BaseObjectTypeState(); type.SymbolicName = name; type.SuperTypeId = ObjectTypeIds.BaseObjectType; type.NodeId = new NodeId(path, NamespaceIndex); type.BrowseName = new QualifiedName(name, NamespaceIndex); type.DisplayName = type.BrowseName.Name; type.WriteMask = AttributeWriteMask.None; type.UserWriteMask = AttributeWriteMask.None; type.IsAbstract = false; IList <IReference> references = null; if (!externalReferences.TryGetValue(ObjectTypeIds.BaseObjectType, out references)) { externalReferences[ObjectTypeIds.BaseObjectType] = references = new List <IReference>(); } references.Add(new NodeStateReference(ReferenceTypes.HasSubtype, false, type.NodeId)); if (parent != null) { parent.AddReference(ReferenceTypes.Organizes, false, type.NodeId); type.AddReference(ReferenceTypes.Organizes, true, parent.NodeId); } AddPredefinedNode(SystemContext, type); return(type); }
/// <summary> /// Updates the event types in cache with the most recent info fetched from the AE server. /// </summary> public void UpdateCache(ServerSystemContext context, ushort namespaceIndex) { // clear the existing nodes. EventTypeNodes = new NodeIdDictionary <BaseObjectTypeState>(); Attributes = new Dictionary <int, int[]>(); TypeTable typeTable = context.TypeTable as TypeTable; // rebuild from the recently fetched list. for (int ii = 0; ii < EventTypes.Count; ii++) { // save the attributes for use when creating filters. if (EventTypes[ii].EventTypeMapping != EventTypeMapping.ConditionClassType && !Attributes.ContainsKey(EventTypes[ii].CategoryId)) { EventType eventType = EventTypes[ii]; int[] attributeIds = new int[eventType.Attributes.Count]; for (int jj = 0; jj < attributeIds.Length; jj++) { attributeIds[jj] = eventType.Attributes[jj].Id; } Attributes.Add(EventTypes[ii].CategoryId, attributeIds); } AeEventTypeState node = new AeEventTypeState(EventTypes[ii], namespaceIndex); BaseObjectTypeState mappingNode = null; if (!EventTypeNodes.TryGetValue(node.SuperTypeId, out mappingNode)) { mappingNode = new AeEventTypeMappingState(node.EventType.EventTypeMapping, namespaceIndex); EventTypeNodes.Add(mappingNode.NodeId, mappingNode); // ensure the mapping node is in the type table. if (typeTable != null) { if (!typeTable.IsKnown(mappingNode.NodeId)) { typeTable.AddSubtype(mappingNode.NodeId, mappingNode.SuperTypeId); } } } EventTypeNodes.Add(node.NodeId, node); // ensure the type node is in the type table. if (typeTable != null) { if (!typeTable.IsKnown(node.NodeId)) { typeTable.AddSubtype(node.NodeId, mappingNode.NodeId); } } } }
/// <summary> /// Returns the type identified by the category id and condition name. /// </summary> public AeEventTypeState FindType(ServerSystemContext context, NodeId nodeId) { if (NodeId.IsNull(nodeId)) { return(null); } BaseObjectTypeState eventType = null; if (!EventTypeNodes.TryGetValue(nodeId, out eventType)) { return(null); } return(eventType as AeEventTypeState); }
/// <summary> /// Converts a ReferenceDescription to an IReference. /// </summary> private IReference ToReference(ReferenceDescription reference) { if (reference.NodeId.IsAbsolute || reference.TypeDefinition.IsAbsolute) { return(new NodeStateReference(reference.ReferenceTypeId, !reference.IsForward, reference.NodeId)); } if (m_source != null && (reference.NodeId == ObjectIds.ObjectsFolder || reference.NodeId == ObjectIds.Server)) { return(new NodeStateReference(reference.ReferenceTypeId, !reference.IsForward, m_rootId)); } NodeState target = null; switch (reference.NodeClass) { case NodeClass.DataType: { target = new DataTypeState(); break; } case NodeClass.Method: { target = new MethodState(null); break; } case NodeClass.Object: { target = new BaseObjectState(null); break; } case NodeClass.ObjectType: { target = new BaseObjectTypeState(); break; } case NodeClass.ReferenceType: { target = new ReferenceTypeState(); break; } case NodeClass.Variable: { target = new BaseDataVariableState(null); break; } case NodeClass.VariableType: { target = new BaseDataVariableTypeState(); break; } case NodeClass.View: { target = new ViewState(); break; } } target.NodeId = m_mapper.ToLocalId((NodeId)reference.NodeId); target.BrowseName = m_mapper.ToLocalName(reference.BrowseName); target.DisplayName = reference.DisplayName; if (target is BaseInstanceState) { ((BaseInstanceState)target).TypeDefinitionId = m_mapper.ToLocalId((NodeId)reference.TypeDefinition); } return(new NodeStateReference(reference.ReferenceTypeId, !reference.IsForward, target)); }
/// <summary> /// Helper to create an ObjectType-Node. Note: __NO__ NodeId is created by the default! /// Must be done by outer functionality!! /// </summary> /// <param name="browseDisplayName">Name displayed in the node tree</param> /// <param name="superTypeId">Base class or similar</param> /// <param name="presetNodeId">Preset the NodeId</param> /// <param name="descriptionKey">Lookup a Description on AAS literal/ refSemantics</param> /// <param name="modellingRule">Modeling Rule, if not None</param> /// <returns>THe node</returns> public static BaseObjectTypeState CreateObjectType( string browseDisplayName, NodeId superTypeId, NodeId presetNodeId = null, string descriptionKey = null, ModellingRule modellingRule = ModellingRule.None) { var x = new BaseObjectTypeState(); x.BrowseName = "" + browseDisplayName; x.DisplayName = "" + browseDisplayName; x.Description = new LocalizedText("en", browseDisplayName); x.Description = SetLocalizedTextWithDescription(x.Description, descriptionKey); x.SuperTypeId = superTypeId; if (presetNodeId != null) { x.NodeId = presetNodeId; } CheckSetModellingRule(modellingRule, x); return(x); }
/// <summary> /// Returns the node for the event type mapping identified by the node id. /// </summary> public AeEventTypeMappingState GetMappingNode(ServerSystemContext context, NodeId nodeId) { BaseObjectTypeState objectType = null; if (!EventTypeNodes.TryGetValue(nodeId, out objectType)) { return(null); } AeEventTypeMappingState mappingNode = objectType as AeEventTypeMappingState; if (mappingNode == null) { return(null); } if (context.TypeTable.FindSubTypes(mappingNode.NodeId).Count == 0) { return(null); } return(mappingNode); }
/// <summary> /// Imports a node from the set. /// </summary> private NodeState Import(ISystemContext context, UANode node) { NodeState importedNode = null; NodeClass nodeClass = NodeClass.Unspecified; if (node is UAObject) { nodeClass = NodeClass.Object; } else if (node is UAVariable) { nodeClass = NodeClass.Variable; } else if (node is UAMethod) { nodeClass = NodeClass.Method; } else if (node is UAObjectType) { nodeClass = NodeClass.ObjectType; } else if (node is UAVariableType) { nodeClass = NodeClass.VariableType; } else if (node is UADataType) { nodeClass = NodeClass.DataType; } else if (node is UAReferenceType) { nodeClass = NodeClass.ReferenceType; } else if (node is UAView) { nodeClass = NodeClass.View; } switch (nodeClass) { case NodeClass.Object: { UAObject o = (UAObject)node; BaseObjectState value = new BaseObjectState(null); value.EventNotifier = o.EventNotifier; importedNode = value; break; } case NodeClass.Variable: { UAVariable o = (UAVariable)node; NodeId typeDefinitionId = null; if (node.References != null) { for (int ii = 0; ii < node.References.Length; ii++) { Opc.Ua.NodeId referenceTypeId = ImportNodeId(node.References[ii].ReferenceType, context.NamespaceUris, true); bool isInverse = !node.References[ii].IsForward; Opc.Ua.ExpandedNodeId targetId = ImportExpandedNodeId(node.References[ii].Value, context.NamespaceUris, context.ServerUris); if (referenceTypeId == ReferenceTypeIds.HasTypeDefinition && !isInverse) { typeDefinitionId = Opc.Ua.ExpandedNodeId.ToNodeId(targetId, context.NamespaceUris); break; } } } BaseVariableState value = null; if (typeDefinitionId == Opc.Ua.VariableTypeIds.PropertyType) { value = new PropertyState(null); } else { value = new BaseDataVariableState(null); } value.DataType = ImportNodeId(o.DataType, context.NamespaceUris, true); value.ValueRank = o.ValueRank; value.ArrayDimensions = ImportArrayDimensions(o.ArrayDimensions); value.AccessLevelEx = o.AccessLevel; value.UserAccessLevel = (byte)(o.AccessLevel & 0xFF); value.MinimumSamplingInterval = o.MinimumSamplingInterval; value.Historizing = o.Historizing; if (o.Value != null) { XmlDecoder decoder = CreateDecoder(context, o.Value); TypeInfo typeInfo = null; value.Value = decoder.ReadVariantContents(out typeInfo); decoder.Close(); } importedNode = value; break; } case NodeClass.Method: { UAMethod o = (UAMethod)node; MethodState value = new MethodState(null); value.Executable = o.Executable; value.UserExecutable = o.Executable; value.TypeDefinitionId = ImportNodeId(o.MethodDeclarationId, context.NamespaceUris, true); importedNode = value; break; } case NodeClass.View: { UAView o = (UAView)node; ViewState value = new ViewState(); value.ContainsNoLoops = o.ContainsNoLoops; importedNode = value; break; } case NodeClass.ObjectType: { UAObjectType o = (UAObjectType)node; BaseObjectTypeState value = new BaseObjectTypeState(); value.IsAbstract = o.IsAbstract; importedNode = value; break; } case NodeClass.VariableType: { UAVariableType o = (UAVariableType)node; BaseVariableTypeState value = new BaseDataVariableTypeState(); value.IsAbstract = o.IsAbstract; value.DataType = ImportNodeId(o.DataType, context.NamespaceUris, true); value.ValueRank = o.ValueRank; value.ArrayDimensions = ImportArrayDimensions(o.ArrayDimensions); if (o.Value != null) { XmlDecoder decoder = CreateDecoder(context, o.Value); TypeInfo typeInfo = null; value.Value = decoder.ReadVariantContents(out typeInfo); decoder.Close(); } importedNode = value; break; } case NodeClass.DataType: { UADataType o = (UADataType)node; DataTypeState value = new DataTypeState(); value.IsAbstract = o.IsAbstract; Opc.Ua.DataTypeDefinition dataTypeDefinition = Import(o, o.Definition, context.NamespaceUris); value.DataTypeDefinition = new ExtensionObject(dataTypeDefinition); value.Purpose = o.Purpose; value.DataTypeModifier = DataTypeModifier.None; if (o.Definition != null) { if (o.Definition.IsOptionSet) { value.DataTypeModifier = DataTypeModifier.OptionSet; } else if (o.Definition.IsUnion) { value.DataTypeModifier = DataTypeModifier.Union; } } importedNode = value; break; } case NodeClass.ReferenceType: { UAReferenceType o = (UAReferenceType)node; ReferenceTypeState value = new ReferenceTypeState(); value.IsAbstract = o.IsAbstract; value.InverseName = Import(o.InverseName); value.Symmetric = o.Symmetric; importedNode = value; break; } } importedNode.NodeId = ImportNodeId(node.NodeId, context.NamespaceUris, false); importedNode.BrowseName = ImportQualifiedName(node.BrowseName, context.NamespaceUris); importedNode.DisplayName = Import(node.DisplayName); if (importedNode.DisplayName == null) { importedNode.DisplayName = new Ua.LocalizedText(importedNode.BrowseName.Name); } importedNode.Description = Import(node.Description); importedNode.Categories = (node.Category != null && node.Category.Length > 0) ? node.Category : null; importedNode.ReleaseStatus = node.ReleaseStatus; importedNode.WriteMask = (AttributeWriteMask)node.WriteMask; importedNode.UserWriteMask = (AttributeWriteMask)node.UserWriteMask; importedNode.Extensions = node.Extensions; if (!String.IsNullOrEmpty(node.SymbolicName)) { importedNode.SymbolicName = node.SymbolicName; } if (node.References != null) { BaseInstanceState instance = importedNode as BaseInstanceState; BaseTypeState type = importedNode as BaseTypeState; for (int ii = 0; ii < node.References.Length; ii++) { Opc.Ua.NodeId referenceTypeId = ImportNodeId(node.References[ii].ReferenceType, context.NamespaceUris, true); bool isInverse = !node.References[ii].IsForward; Opc.Ua.ExpandedNodeId targetId = ImportExpandedNodeId(node.References[ii].Value, context.NamespaceUris, context.ServerUris); if (instance != null) { if (referenceTypeId == ReferenceTypeIds.HasModellingRule && !isInverse) { instance.ModellingRuleId = Opc.Ua.ExpandedNodeId.ToNodeId(targetId, context.NamespaceUris); continue; } if (referenceTypeId == ReferenceTypeIds.HasTypeDefinition && !isInverse) { instance.TypeDefinitionId = Opc.Ua.ExpandedNodeId.ToNodeId(targetId, context.NamespaceUris); continue; } } if (type != null) { if (referenceTypeId == ReferenceTypeIds.HasSubtype && isInverse) { type.SuperTypeId = Opc.Ua.ExpandedNodeId.ToNodeId(targetId, context.NamespaceUris); continue; } } importedNode.AddReference(referenceTypeId, isInverse, targetId); } } return(importedNode); }
/// <summary> /// Adds a node to the set. /// </summary> public void Export(ISystemContext context, NodeState node, bool outputRedundantNames = true) { if (node == null) { throw new ArgumentNullException(nameof(node)); } if (Opc.Ua.NodeId.IsNull(node.NodeId)) { throw new ArgumentException("A non-null NodeId must be specified."); } UANode exportedNode = null; switch (node.NodeClass) { case NodeClass.Object: { BaseObjectState o = (BaseObjectState)node; UAObject value = new UAObject(); value.EventNotifier = o.EventNotifier; if (o.Parent != null) { value.ParentNodeId = ExportAlias(o.Parent.NodeId, context.NamespaceUris); } exportedNode = value; break; } case NodeClass.Variable: { BaseVariableState o = (BaseVariableState)node; UAVariable value = new UAVariable(); value.DataType = ExportAlias(o.DataType, context.NamespaceUris); value.ValueRank = o.ValueRank; value.ArrayDimensions = Export(o.ArrayDimensions); value.AccessLevel = o.AccessLevelEx; value.MinimumSamplingInterval = o.MinimumSamplingInterval; value.Historizing = o.Historizing; if (o.Parent != null) { value.ParentNodeId = ExportAlias(o.Parent.NodeId, context.NamespaceUris); } if (o.Value != null) { XmlEncoder encoder = CreateEncoder(context); Variant variant = new Variant(o.Value); encoder.WriteVariantContents(variant.Value, variant.TypeInfo); XmlDocument document = new XmlDocument(); document.InnerXml = encoder.Close(); value.Value = document.DocumentElement; } exportedNode = value; break; } case NodeClass.Method: { MethodState o = (MethodState)node; UAMethod value = new UAMethod(); value.Executable = o.Executable; if (o.TypeDefinitionId != null && !o.TypeDefinitionId.IsNullNodeId && o.TypeDefinitionId != o.NodeId) { value.MethodDeclarationId = Export(o.TypeDefinitionId, context.NamespaceUris); } if (o.Parent != null) { value.ParentNodeId = ExportAlias(o.Parent.NodeId, context.NamespaceUris); } exportedNode = value; break; } case NodeClass.View: { ViewState o = (ViewState)node; UAView value = new UAView(); value.ContainsNoLoops = o.ContainsNoLoops; exportedNode = value; break; } case NodeClass.ObjectType: { BaseObjectTypeState o = (BaseObjectTypeState)node; UAObjectType value = new UAObjectType(); value.IsAbstract = o.IsAbstract; exportedNode = value; break; } case NodeClass.VariableType: { BaseVariableTypeState o = (BaseVariableTypeState)node; UAVariableType value = new UAVariableType(); value.IsAbstract = o.IsAbstract; value.DataType = ExportAlias(o.DataType, context.NamespaceUris); value.ValueRank = o.ValueRank; value.ArrayDimensions = Export(o.ArrayDimensions); if (o.Value != null) { XmlEncoder encoder = CreateEncoder(context); Variant variant = new Variant(o.Value); encoder.WriteVariantContents(variant.Value, variant.TypeInfo); XmlDocument document = new XmlDocument(); document.InnerXml = encoder.Close(); value.Value = document.DocumentElement; } exportedNode = value; break; } case NodeClass.DataType: { DataTypeState o = (DataTypeState)node; UADataType value = new UADataType(); value.IsAbstract = o.IsAbstract; value.Definition = Export(o, o.DataTypeDefinition, context.NamespaceUris, outputRedundantNames); value.Purpose = o.Purpose; exportedNode = value; break; } case NodeClass.ReferenceType: { ReferenceTypeState o = (ReferenceTypeState)node; UAReferenceType value = new UAReferenceType(); value.IsAbstract = o.IsAbstract; if (!Opc.Ua.LocalizedText.IsNullOrEmpty(o.InverseName)) { value.InverseName = Export(new Opc.Ua.LocalizedText[] { o.InverseName }); } value.Symmetric = o.Symmetric; exportedNode = value; break; } } exportedNode.NodeId = Export(node.NodeId, context.NamespaceUris); exportedNode.BrowseName = Export(node.BrowseName, context.NamespaceUris); if (outputRedundantNames || node.DisplayName.Text != node.BrowseName.Name) { exportedNode.DisplayName = Export(new Opc.Ua.LocalizedText[] { node.DisplayName }); } else { exportedNode.DisplayName = null; } if (node.Description != null && !String.IsNullOrEmpty(node.Description.Text)) { exportedNode.Description = Export(new Opc.Ua.LocalizedText[] { node.Description }); } else { exportedNode.Description = new LocalizedText[0]; } exportedNode.Category = (node.Categories != null && node.Categories.Count > 0) ? new List <string>(node.Categories).ToArray() : null; exportedNode.ReleaseStatus = node.ReleaseStatus; exportedNode.WriteMask = (uint)node.WriteMask; exportedNode.UserWriteMask = (uint)node.UserWriteMask; exportedNode.Extensions = node.Extensions; if (!String.IsNullOrEmpty(node.SymbolicName) && node.SymbolicName != node.BrowseName.Name) { exportedNode.SymbolicName = node.SymbolicName; } // export references. INodeBrowser browser = node.CreateBrowser(context, null, null, true, BrowseDirection.Both, null, null, true); List <Reference> exportedReferences = new List <Reference>(); IReference reference = browser.Next(); while (reference != null) { if (node.NodeClass == NodeClass.Method) { if (!reference.IsInverse && reference.ReferenceTypeId == ReferenceTypeIds.HasTypeDefinition) { reference = browser.Next(); continue; } } Reference exportedReference = new Reference(); exportedReference.ReferenceType = ExportAlias(reference.ReferenceTypeId, context.NamespaceUris); exportedReference.IsForward = !reference.IsInverse; exportedReference.Value = Export(reference.TargetId, context.NamespaceUris, context.ServerUris); exportedReferences.Add(exportedReference); reference = browser.Next(); } exportedNode.References = exportedReferences.ToArray(); // add node to list. UANode[] nodes = null; int count = 1; if (this.Items == null) { nodes = new UANode[count]; } else { count += this.Items.Length; nodes = new UANode[count]; Array.Copy(this.Items, nodes, this.Items.Length); } nodes[count - 1] = exportedNode; this.Items = nodes; // recusively process children. List <BaseInstanceState> children = new List <BaseInstanceState>(); node.GetChildren(context, children); for (int ii = 0; ii < children.Count; ii++) { Export(context, children[ii], outputRedundantNames); } }
/// <summary> /// Convert to stack object /// </summary> /// <param name="nodeModel"></param> /// <param name="context"></param> /// <param name="parent"></param> /// <returns></returns> public static NodeState ToNodeState(this BaseNodeModel nodeModel, ISystemContext context, NodeState parent = null) { NodeState state; switch (nodeModel) { case ViewNodeModel viewState: state = new ViewState { ContainsNoLoops = viewState.ContainsNoLoops ?? false, EventNotifier = viewState.EventNotifier ?? EventNotifiers.None, }; break; case TypeNodeModel typeState: switch (typeState) { case VariableTypeNodeModel variableType: switch (variableType) { case DataVariableTypeNodeModel data: state = new BaseDataVariableTypeState(); break; case PropertyTypeNodeModel property: state = new PropertyTypeState(); break; default: return(null); } var baseVariableTypeState = state as BaseVariableTypeState; baseVariableTypeState.ArrayDimensions = variableType.ArrayDimensions; baseVariableTypeState.DataType = variableType.DataType; baseVariableTypeState.ValueRank = variableType.ValueRank ?? ValueRanks.Scalar; baseVariableTypeState.WrappedValue = variableType.Value ?? Variant.Null; break; case ObjectTypeNodeModel objectType: state = new BaseObjectTypeState(); break; case ReferenceTypeNodeModel referenceType: state = new ReferenceTypeState { Symmetric = referenceType.Symmetric ?? false, InverseName = referenceType.InverseName }; break; case DataTypeNodeModel dataType: state = new DataTypeState { // Definition = dataType.Definition.ToDataTypeDefinition() }; break; default: return(null); } var baseTypeState = state as BaseTypeState; baseTypeState.IsAbstract = typeState.IsAbstract ?? false; break; case InstanceNodeModel instanceState: switch (instanceState) { case VariableNodeModel variable: switch (variable) { case DataVariableNodeModel data: state = new BaseDataVariableState(parent); break; case PropertyNodeModel property: state = new PropertyState(parent); break; default: return(null); } var baseVariableState = state as BaseVariableState; baseVariableState.ArrayDimensions = variable.ArrayDimensions; baseVariableState.DataType = variable.DataType; baseVariableState.ValueRank = variable.ValueRank ?? ValueRanks.Scalar; baseVariableState.Value = variable.Value?.Value; baseVariableState.AccessLevel = variable.AccessLevel ?? AccessLevels.CurrentRead; baseVariableState.UserAccessLevel = variable.UserAccessLevel ?? AccessLevels.CurrentRead; baseVariableState.IsValueType = variable.IsValueType; baseVariableState.Historizing = variable.Historizing ?? false; baseVariableState.MinimumSamplingInterval = variable.MinimumSamplingInterval ?? 0.0; baseVariableState.ModellingRuleId = variable.ModellingRuleId; baseVariableState.NumericId = variable.NumericId; baseVariableState.ReferenceTypeId = variable.ReferenceTypeId; baseVariableState.StatusCode = variable.StatusCode ?? StatusCodes.Good; baseVariableState.Timestamp = variable.Timestamp ?? DateTime.MinValue; baseVariableState.TypeDefinitionId = variable.TypeDefinitionId; break; case ObjectNodeModel obj: state = new BaseObjectState(parent) { EventNotifier = obj.EventNotifier ?? EventNotifiers.None }; break; case MethodNodeModel method: state = new MethodState(parent) { UserExecutable = method.UserExecutable, Executable = method.Executable, MethodDeclarationId = method.MethodDeclarationId }; break; default: return(null); } break; default: return(null); } state.BrowseName = nodeModel.BrowseName; state.Description = nodeModel.Description; state.DisplayName = nodeModel.DisplayName; state.Handle = nodeModel.Handle; state.NodeId = nodeModel.NodeId; state.SymbolicName = nodeModel.SymbolicName; state.WriteMask = nodeModel.WriteMask ?? AttributeWriteMask.None; state.UserWriteMask = nodeModel.UserWriteMask ?? AttributeWriteMask.None; state.Initialized = true; foreach (var child in nodeModel.GetChildren(context)) { state.AddChild(child.ToNodeState(context, state) as BaseInstanceState); } foreach (var reference in nodeModel.References) { state.AddReference(reference.ReferenceTypeId, reference.IsInverse, reference.TargetId); } return(state); }
/// <summary> /// Verifies that the specified node exists. /// </summary> protected override NodeState ValidateNode( ServerSystemContext context, NodeHandle handle, IDictionary <NodeId, NodeState> cache) { // not valid if no root. if (handle == null) { return(null); } // check if previously validated. if (handle.Validated) { return(handle.Node); } NodeState target = null; // check if already in the cache. if (cache != null) { if (cache.TryGetValue(handle.NodeId, out target)) { // nulls mean a NodeId which was previously found to be invalid has been referenced again. if (target == null) { return(null); } handle.Node = target; handle.Validated = true; return(handle.Node); } target = null; } try { // check if the node id has been parsed. AeParsedNodeId parsedNodeId = handle.ParsedNodeId as AeParsedNodeId; if (parsedNodeId == null) { return(null); } ComAeClient client = m_system.SelectClient(context, false); switch (parsedNodeId.RootType) { case AeModelUtils.AeSimpleEventType: case AeModelUtils.AeTrackingEventType: case AeModelUtils.AeConditionEventType: { if (m_typeCache == null) { return(null); } BaseObjectTypeState eventTypeNode = null; NodeId rootId = AeParsedNodeId.Construct(parsedNodeId.RootType, parsedNodeId.CategoryId, parsedNodeId.ConditionName, parsedNodeId.NamespaceIndex); if (!m_typeCache.EventTypeNodes.TryGetValue(rootId, out eventTypeNode)) { return(null); } target = eventTypeNode; break; } case AeModelUtils.AeArea: { ComAeBrowserClient browser = new ComAeBrowserClient(client, null); target = browser.FindArea(context, parsedNodeId.RootId, NamespaceIndex); browser.Dispose(); handle.Validated = true; handle.Node = target; return(handle.Node); } case AeModelUtils.AeSource: { ComAeBrowserClient browser = new ComAeBrowserClient(client, null); target = browser.FindSource(context, parsedNodeId.RootId, parsedNodeId.ComponentPath, NamespaceIndex); browser.Dispose(); handle.Validated = true; handle.Node = target; return(handle.Node); } case AeModelUtils.AeCondition: { target = new AeConditionState(context, handle, m_templateAlarm.Acknowledge); break; } } // node does not exist. if (target == null) { return(null); } if (!String.IsNullOrEmpty(parsedNodeId.ComponentPath)) { // validate component. NodeState component = target.FindChildBySymbolicName(context, parsedNodeId.ComponentPath); // component does not exist. if (component == null) { return(null); } target = component; } // found a valid component. handle.Validated = true; handle.Node = target; return(handle.Node); } finally { // store the node in the cache to optimize subsequent lookups. if (cache != null) { cache.Add(handle.NodeId, target); } } }
/// <summary> /// Imports a node from the set. /// </summary> private NodeState Import(ISystemContext context, UANode node) { NodeState importedNode = null; NodeClass nodeClass = NodeClass.Unspecified; if (node is UAObject) nodeClass = NodeClass.Object; else if (node is UAVariable) nodeClass = NodeClass.Variable; else if (node is UAMethod) nodeClass = NodeClass.Method; else if (node is UAObjectType) nodeClass = NodeClass.ObjectType; else if (node is UAVariableType) nodeClass = NodeClass.VariableType; else if (node is UADataType) nodeClass = NodeClass.DataType; else if (node is UAReferenceType) nodeClass = NodeClass.ReferenceType; else if (node is UAView) nodeClass = NodeClass.View; switch (nodeClass) { case NodeClass.Object: { UAObject o = (UAObject)node; BaseObjectState value = new BaseObjectState(null); value.EventNotifier = o.EventNotifier; importedNode = value; break; } case NodeClass.Variable: { UAVariable o = (UAVariable)node; NodeId typeDefinitionId = null; if (node.References != null) { for (int ii = 0; ii < node.References.Length; ii++) { Opc.Ua.NodeId referenceTypeId = ImportNodeId(node.References[ii].ReferenceType, context.NamespaceUris, true); bool isInverse = !node.References[ii].IsForward; Opc.Ua.ExpandedNodeId targetId = ImportExpandedNodeId(node.References[ii].Value, context.NamespaceUris, context.ServerUris); if (referenceTypeId == ReferenceTypeIds.HasTypeDefinition && !isInverse) { typeDefinitionId = Opc.Ua.ExpandedNodeId.ToNodeId(targetId, context.NamespaceUris); break; } } } BaseVariableState value = null; if (typeDefinitionId == Opc.Ua.VariableTypeIds.PropertyType) { value = new PropertyState(null); } else { value = new BaseDataVariableState(null); } value.DataType = ImportNodeId(o.DataType, context.NamespaceUris, true); value.ValueRank = o.ValueRank; value.ArrayDimensions = ImportArrayDimensions(o.ArrayDimensions); value.AccessLevel = o.AccessLevel; value.UserAccessLevel = o.UserAccessLevel; value.MinimumSamplingInterval = o.MinimumSamplingInterval; value.Historizing = o.Historizing; if (o.Value != null) { XmlDecoder decoder = CreateDecoder(context, o.Value); TypeInfo typeInfo = null; value.Value = decoder.ReadVariantContents(out typeInfo); decoder.Close(); } importedNode = value; break; } case NodeClass.Method: { UAMethod o = (UAMethod)node; MethodState value = new MethodState(null); value.Executable = o.Executable; value.UserExecutable = o.UserExecutable; importedNode = value; break; } case NodeClass.View: { UAView o = (UAView)node; ViewState value = new ViewState(); value.ContainsNoLoops = o.ContainsNoLoops; importedNode = value; break; } case NodeClass.ObjectType: { UAObjectType o = (UAObjectType)node; BaseObjectTypeState value = new BaseObjectTypeState(); value.IsAbstract = o.IsAbstract; importedNode = value; break; } case NodeClass.VariableType: { UAVariableType o = (UAVariableType)node; BaseVariableTypeState value = new BaseDataVariableTypeState(); value.IsAbstract = o.IsAbstract; value.DataType = ImportNodeId(o.DataType, context.NamespaceUris, true); value.ValueRank = o.ValueRank; value.ArrayDimensions = ImportArrayDimensions(o.ArrayDimensions); if (o.Value != null) { XmlDecoder decoder = CreateDecoder(context, o.Value); TypeInfo typeInfo = null; value.Value = decoder.ReadVariantContents(out typeInfo); decoder.Close(); } importedNode = value; break; } case NodeClass.DataType: { UADataType o = (UADataType)node; DataTypeState value = new DataTypeState(); value.IsAbstract = o.IsAbstract; value.Definition = Import(o.Definition, context.NamespaceUris); importedNode = value; break; } case NodeClass.ReferenceType: { UAReferenceType o = (UAReferenceType)node; ReferenceTypeState value = new ReferenceTypeState(); value.IsAbstract = o.IsAbstract; value.InverseName = Import(o.InverseName); value.Symmetric = o.Symmetric; importedNode = value; break; } } importedNode.NodeId = ImportNodeId(node.NodeId, context.NamespaceUris, false); importedNode.BrowseName = ImportQualifiedName(node.BrowseName, context.NamespaceUris); importedNode.DisplayName = Import(node.DisplayName); importedNode.Description = Import(node.Description); importedNode.WriteMask = (AttributeWriteMask)node.WriteMask; importedNode.UserWriteMask = (AttributeWriteMask)node.UserWriteMask; if (!String.IsNullOrEmpty(node.SymbolicName)) { importedNode.SymbolicName = node.SymbolicName; } if (node.References != null) { BaseInstanceState instance = importedNode as BaseInstanceState; BaseTypeState type = importedNode as BaseTypeState; for (int ii = 0; ii < node.References.Length; ii++) { Opc.Ua.NodeId referenceTypeId = ImportNodeId(node.References[ii].ReferenceType, context.NamespaceUris, true); bool isInverse = !node.References[ii].IsForward; Opc.Ua.ExpandedNodeId targetId = ImportExpandedNodeId(node.References[ii].Value, context.NamespaceUris, context.ServerUris); if (instance != null) { if (referenceTypeId == ReferenceTypeIds.HasModellingRule && !isInverse) { instance.ModellingRuleId = Opc.Ua.ExpandedNodeId.ToNodeId(targetId, context.NamespaceUris); continue; } if (referenceTypeId == ReferenceTypeIds.HasTypeDefinition && !isInverse) { instance.TypeDefinitionId = Opc.Ua.ExpandedNodeId.ToNodeId(targetId, context.NamespaceUris); continue; } } if (type != null) { if (referenceTypeId == ReferenceTypeIds.HasSubtype && isInverse) { type.SuperTypeId = Opc.Ua.ExpandedNodeId.ToNodeId(targetId, context.NamespaceUris); continue; } } importedNode.AddReference(referenceTypeId, isInverse, targetId); } } return importedNode; }
/// <summary> /// Does any initialization required before the address space can be used. /// </summary> /// <remarks> /// The externalReferences is an out parameter that allows the node manager to link to nodes /// in other node managers. For example, the 'Objects' node is managed by the CoreNodeManager and /// should have a reference to the root folder node(s) exposed by this node manager. /// </remarks> public override void CreateAddressSpace(IDictionary <NodeId, IList <IReference> > externalReferences) { lock (Lock) { //counter for the NodeId identifier: uint id = 1; // Define the nodes: #region sample nodes //----------------- A few examples of hard coded nodes in the Address Space ------------------- //a first node: BaseObjectState testObjectNode = new BaseObjectState(null); // Set the attributes: testObjectNode.NodeId = new NodeId(id++, NamespaceIndex); testObjectNode.BrowseName = new QualifiedName("test_ObjectNode", NamespaceIndex); testObjectNode.DisplayName = testObjectNode.BrowseName.Name; testObjectNode.TypeDefinitionId = ObjectTypeIds.BaseObjectType; // ensure testObjectNode can be found via the server object: add references to/from it! IList <IReference> references = null; if (!externalReferences.TryGetValue(ObjectIds.ObjectsFolder, out references)) { externalReferences[ObjectIds.ObjectsFolder] = references = new List <IReference>(); } testObjectNode.AddReference(ReferenceTypeIds.Organizes, true, ObjectIds.ObjectsFolder); references.Add(new NodeStateReference(ReferenceTypeIds.Organizes, false, testObjectNode.NodeId)); //a second node: PropertyState testPropertyNode = new PropertyState(testObjectNode); // Set the attributes: testPropertyNode.NodeId = new NodeId(id++, NamespaceIndex); testPropertyNode.BrowseName = new QualifiedName("test_PropertyNode", NamespaceIndex); testPropertyNode.DisplayName = testPropertyNode.BrowseName.Name; testPropertyNode.TypeDefinitionId = VariableTypeIds.PropertyType; testPropertyNode.ReferenceTypeId = ReferenceTypeIds.HasProperty; testPropertyNode.DataType = DataTypeIds.Int32; testPropertyNode.ValueRank = ValueRanks.OneDimension; testPropertyNode.ArrayDimensions = new ReadOnlyList <uint>(new uint[] { 5 }); testPropertyNode.Value = new int[] { 7, -18, 56, 0, 3 }; //add this node as a child of the previous node: testObjectNode.AddChild(testPropertyNode); // save in dictionary. AddPredefinedNode(SystemContext, testObjectNode); //--------------------------------------------------------------------------------------------- #endregion #region tetris simulation nodes //------------------------------ The nodes for the tetris simulation -------------------------- // The object node under wich the other nodes containing the data will be organized: BaseObjectState tetrisSimulationNode = new BaseObjectState(null); tetrisSimulationNode.NodeId = new NodeId(id++, NamespaceIndex); tetrisSimulationNode.BrowseName = new QualifiedName("Tetris_Simulation", NamespaceIndex); tetrisSimulationNode.DisplayName = tetrisSimulationNode.BrowseName.Name; tetrisSimulationNode.SymbolicName = tetrisSimulationNode.BrowseName.Name; tetrisSimulationNode.TypeDefinitionId = ObjectTypeIds.BaseObjectType; // ensure tetrisSimulationNode can be found via the server object: add references to/from it! references = null; if (!externalReferences.TryGetValue(ObjectIds.ObjectsFolder, out references)) { externalReferences[ObjectIds.ObjectsFolder] = references = new List <IReference>(); } // Forward Reference FROM the ObjectsFolder node TO our tetris node: references.Add(new NodeStateReference(ReferenceTypeIds.Organizes, false, tetrisSimulationNode.NodeId)); // Inverse Reference FROM our tetris node TO the ObjectsFolder node: tetrisSimulationNode.AddReference(ReferenceTypeIds.Organizes, true, ObjectIds.ObjectsFolder); // -------------------- Nodes containing data ------------------- // The nodes containing some simulated tetris data: //Score: BaseDataVariableState simulatedScoreNode = new BaseDataVariableState(tetrisSimulationNode); simulatedScoreNode.NodeId = new NodeId(id++, NamespaceIndex); simulatedScoreNode.BrowseName = new QualifiedName("simulated_Score", NamespaceIndex); simulatedScoreNode.DisplayName = simulatedScoreNode.BrowseName.Name; simulatedScoreNode.TypeDefinitionId = VariableTypeIds.BaseDataVariableType; simulatedScoreNode.ReferenceTypeId = ReferenceTypeIds.HasComponent; simulatedScoreNode.DataType = DataTypeIds.Int32; simulatedScoreNode.ValueRank = ValueRanks.Scalar; //add the reference from the Tetris_Simulation Object Node to this one: tetrisSimulationNode.AddChild(simulatedScoreNode); //Game Over status: BaseDataVariableState simulatedGameOverNode = new BaseDataVariableState(tetrisSimulationNode); simulatedGameOverNode.NodeId = new NodeId(id++, NamespaceIndex); simulatedGameOverNode.BrowseName = new QualifiedName("simulated_GameOver", NamespaceIndex); simulatedGameOverNode.DisplayName = simulatedGameOverNode.BrowseName.Name; simulatedGameOverNode.TypeDefinitionId = VariableTypeIds.BaseDataVariableType; simulatedGameOverNode.ReferenceTypeId = ReferenceTypeIds.HasComponent; simulatedGameOverNode.DataType = DataTypeIds.Boolean; simulatedGameOverNode.ValueRank = ValueRanks.Scalar; //add the reference from the Tetris_Simulation Object Node to this one: tetrisSimulationNode.AddChild(simulatedGameOverNode); //Paused status: BaseDataVariableState simulatedPausedNode = new BaseDataVariableState(tetrisSimulationNode); simulatedPausedNode.NodeId = new NodeId(id++, NamespaceIndex); simulatedPausedNode.BrowseName = new QualifiedName("simulated_Paused", NamespaceIndex); simulatedPausedNode.DisplayName = simulatedPausedNode.BrowseName.Name; simulatedPausedNode.TypeDefinitionId = VariableTypeIds.BaseDataVariableType; simulatedPausedNode.ReferenceTypeId = ReferenceTypeIds.HasComponent; simulatedPausedNode.DataType = DataTypeIds.Boolean; simulatedPausedNode.ValueRank = ValueRanks.Scalar; simulatedPausedNode.AccessLevel = AccessLevels.CurrentReadOrWrite; simulatedPausedNode.Value = false; //add the reference from the Tetris_Simulation Object Node to this one: tetrisSimulationNode.AddChild(simulatedPausedNode); //--------------------------------------------------------------- AddPredefinedNode(SystemContext, tetrisSimulationNode); //--------------------------------------------------------------------------------------------- #endregion #region teris game nodes //------------------------------ The nodes for the tetris game -------------------------------- // The object node under wich the other nodes containing the data will be organized: BaseObjectState tetrisGameNode = new BaseObjectState(null); tetrisGameNode.NodeId = new NodeId(id++, NamespaceIndex); tetrisGameNode.BrowseName = new QualifiedName("Tetris_Game", NamespaceIndex); tetrisGameNode.DisplayName = tetrisGameNode.BrowseName.Name; tetrisGameNode.SymbolicName = tetrisGameNode.BrowseName.Name; tetrisGameNode.TypeDefinitionId = ObjectTypeIds.BaseObjectType; // ensure tetrisGameNode can be found via the server object: add references to/from it! references = null; if (!externalReferences.TryGetValue(ObjectIds.ObjectsFolder, out references)) { externalReferences[ObjectIds.ObjectsFolder] = references = new List <IReference>(); } // Forward Reference FROM the ObjectsFolder node TO our tetris node: references.Add(new NodeStateReference(ReferenceTypeIds.Organizes, false, tetrisGameNode.NodeId)); // Inverse Reference FROM our tetris node TO the ObjectsFolder node: tetrisGameNode.AddReference(ReferenceTypeIds.Organizes, true, ObjectIds.ObjectsFolder); //------------- Enable tetris node to report events --------------- //set the tetrisGameNode as EventNotifier: tetrisGameNode.EventNotifier = EventNotifiers.SubscribeToEvents; // Add a HasNotifier reference from Server object to our tetris node: Server.CoreNodeManager.AddReference(ObjectIds.Server, ReferenceTypeIds.HasNotifier, false, tetrisGameNode.NodeId, false); // Also do the inverse: // connect the tetrisGame node to the Server object by making it a Root Notifier (of our Node Manager) AddRootNotifier(tetrisGameNode); // an inverse reference from our tetris node to the Server object is added in here // (Note: A node added as a root notifier will report its events directly to the server object. // This is not UA specific, but an SDK specific implementation.) //----------------------------------------------------------------- // -------------------- Nodes containing data ------------------- // The nodes containing some simulated tetris data: //Score: BaseDataVariableState scoreNode = new BaseDataVariableState(tetrisGameNode); scoreNode.NodeId = new NodeId(id++, NamespaceIndex); scoreNode.BrowseName = new QualifiedName("Score", NamespaceIndex); scoreNode.DisplayName = scoreNode.BrowseName.Name; scoreNode.TypeDefinitionId = VariableTypeIds.BaseDataVariableType; scoreNode.ReferenceTypeId = ReferenceTypeIds.HasComponent; scoreNode.DataType = DataTypeIds.Int32; scoreNode.ValueRank = ValueRanks.Scalar; //add the reference from the Tetris_Game Object Node to this one: tetrisGameNode.AddChild(scoreNode); //Game Over status: BaseDataVariableState gameOverNode = new BaseDataVariableState(tetrisGameNode); gameOverNode.NodeId = new NodeId(id++, NamespaceIndex); gameOverNode.BrowseName = new QualifiedName("GameOver", NamespaceIndex); gameOverNode.DisplayName = gameOverNode.BrowseName.Name; gameOverNode.TypeDefinitionId = VariableTypeIds.BaseDataVariableType; gameOverNode.ReferenceTypeId = ReferenceTypeIds.HasComponent; gameOverNode.DataType = DataTypeIds.Boolean; gameOverNode.ValueRank = ValueRanks.Scalar; //add the reference from the Tetris_Game Object Node to this one: tetrisGameNode.AddChild(gameOverNode); //Paused status: BaseDataVariableState pausedNode = new BaseDataVariableState(tetrisGameNode); pausedNode.NodeId = new NodeId(id++, NamespaceIndex); pausedNode.BrowseName = new QualifiedName("Paused", NamespaceIndex); pausedNode.DisplayName = pausedNode.BrowseName.Name; pausedNode.TypeDefinitionId = VariableTypeIds.BaseDataVariableType; pausedNode.ReferenceTypeId = ReferenceTypeIds.HasComponent; pausedNode.DataType = DataTypeIds.Boolean; pausedNode.ValueRank = ValueRanks.Scalar; //add the reference from the Tetris_Game Object Node to this one: tetrisGameNode.AddChild(pausedNode); //SecondsTillUnpause: BaseDataVariableState secondsTillUnpauseNode = new BaseDataVariableState(tetrisGameNode); secondsTillUnpauseNode.NodeId = new NodeId(id++, NamespaceIndex); secondsTillUnpauseNode.BrowseName = new QualifiedName("Seconds_Till_Unpause", NamespaceIndex); secondsTillUnpauseNode.DisplayName = secondsTillUnpauseNode.BrowseName.Name; secondsTillUnpauseNode.TypeDefinitionId = VariableTypeIds.BaseDataVariableType; secondsTillUnpauseNode.ReferenceTypeId = ReferenceTypeIds.HasComponent; secondsTillUnpauseNode.DataType = DataTypeIds.Int32; secondsTillUnpauseNode.ValueRank = ValueRanks.Scalar; //add the reference from the Tetris_Game Object Node to this one: tetrisGameNode.AddChild(secondsTillUnpauseNode); //SecondsTillUnpause: BaseDataVariableState fieldNode = new BaseDataVariableState(tetrisGameNode); fieldNode.NodeId = new NodeId(id++, NamespaceIndex); fieldNode.BrowseName = new QualifiedName("Field", NamespaceIndex); fieldNode.DisplayName = fieldNode.BrowseName.Name; fieldNode.TypeDefinitionId = VariableTypeIds.BaseDataVariableType; fieldNode.ReferenceTypeId = ReferenceTypeIds.HasComponent; fieldNode.DataType = DataTypeIds.Int32; fieldNode.ValueRank = ValueRanks.TwoDimensions; //fieldNode.ArrayDimensions = ??? // => get the matrix (twodimensional array) dimension lengths: uint x = (uint)m_TetrisGame.DynamicField.GetLength(0); uint y = (uint)m_TetrisGame.DynamicField.GetLength(1); fieldNode.ArrayDimensions = new ReadOnlyList <uint>(new uint[] { x, y }); //add the reference from the Tetris_Game Object Node to this one: tetrisGameNode.AddChild(fieldNode); //--------------------------------------------------------------- AddPredefinedNode(SystemContext, tetrisGameNode); //--------------------------------------------------------------------------------------------- #endregion #region tetris method node //------------------------------ The method node for the tetris game -------------------------- // ------ The method state itself: ------ MethodState pauseMethodNode = new MethodState(tetrisGameNode); pauseMethodNode.NodeId = new NodeId(id++, NamespaceIndex); pauseMethodNode.BrowseName = new QualifiedName("Pause_Method", NamespaceIndex); pauseMethodNode.DisplayName = pauseMethodNode.BrowseName.Name; pauseMethodNode.SymbolicName = pauseMethodNode.BrowseName.Name; pauseMethodNode.Description = new LocalizedText("A method to pause the TetrisGame for X seconds"); pauseMethodNode.ReferenceTypeId = ReferenceTypeIds.HasComponent; pauseMethodNode.UserExecutable = true; pauseMethodNode.Executable = true; // ------ Add the InputArguments: ------ pauseMethodNode.InputArguments = new PropertyState <Argument[]>(pauseMethodNode); pauseMethodNode.InputArguments.NodeId = new NodeId(id++, NamespaceIndex); pauseMethodNode.InputArguments.BrowseName = BrowseNames.InputArguments; pauseMethodNode.InputArguments.DisplayName = new LocalizedText("InputArgs_PauseMethod"); pauseMethodNode.InputArguments.SymbolicName = pauseMethodNode.InputArguments.DisplayName.Text; // These are properties of the method state (closer relation with parent than "HasComponent"): pauseMethodNode.InputArguments.TypeDefinitionId = VariableTypeIds.PropertyType; pauseMethodNode.InputArguments.ReferenceTypeId = ReferenceTypeIds.HasProperty; //Attributes related to the Value (= Argument): pauseMethodNode.InputArguments.DataType = DataTypeIds.Argument; pauseMethodNode.InputArguments.ValueRank = ValueRanks.Scalar; // Create the Argument (= Value of PropertyNode 'InputArguments'): Argument[] args_in = new Argument[1]; // only one inputargument args_in[0] = new Argument(); args_in[0].Name = "SecondsToPause"; args_in[0].Description = "The number of seconds to pause the Tetris Game"; args_in[0].DataType = DataTypeIds.UInt32; args_in[0].ValueRank = ValueRanks.Scalar; // Add the Argument as the Value of the method Node: pauseMethodNode.InputArguments.Value = args_in; // ------ Add the OutputArguments: ------ pauseMethodNode.OutputArguments = new PropertyState <Argument[]>(pauseMethodNode); pauseMethodNode.OutputArguments.NodeId = new NodeId(id++, NamespaceIndex); pauseMethodNode.OutputArguments.BrowseName = BrowseNames.OutputArguments; pauseMethodNode.OutputArguments.DisplayName = new LocalizedText("OutputArgs_PauseMethod"); pauseMethodNode.OutputArguments.SymbolicName = pauseMethodNode.OutputArguments.DisplayName.Text; // These are properties of the method state (closer relation with parent than "HasComponent"): pauseMethodNode.OutputArguments.TypeDefinitionId = VariableTypeIds.PropertyType; pauseMethodNode.OutputArguments.ReferenceTypeId = ReferenceTypeIds.HasProperty; //Attributes related to the Value (= Argument): pauseMethodNode.OutputArguments.DataType = DataTypeIds.Argument; pauseMethodNode.OutputArguments.ValueRank = ValueRanks.Scalar; // Create the Argument (= Value of PropertyNode 'InputArguments'): Argument[] args_out = new Argument[1]; // only one outputargument args_out[0] = new Argument(); args_out[0].Name = "SecondsToPause_StringResult"; args_out[0].Description = "A string telling the Nr. of seconds the game is paused"; args_out[0].DataType = DataTypeIds.String; args_out[0].ValueRank = ValueRanks.Scalar; // Add the Argument as the Value of the method Node: pauseMethodNode.OutputArguments.Value = args_out; // ------ set up myPauseMethod method handler: ------ pauseMethodNode.OnCallMethod = new GenericMethodCalledEventHandler(OnPauseMethod); // (From now on OnPauseMethod(...) will be called whenever this method is called by the client!) // ------ Add the Method Node as child to the Tetris_Game parent node... ------ tetrisGameNode.AddChild(pauseMethodNode); // ------ ... and add it to the predefined nodes: ------ AddPredefinedNode(SystemContext, pauseMethodNode); //--------------------------------------------------------------------------------------------- #endregion #region TetrisLinesMadeEventType //----------------Add the TetrisLinesMadeEventType to the EventTYpe Hierarchy ----------------- // Create the Type information (i.e. Object type with attached properties) // to represent our TetrisLinesMadeEventType (with its 2 properties), // in the OPC UA type model's EventType Hierarchy (which is accessible in the server Address Space) BaseObjectTypeState newEventType = new BaseObjectTypeState(); // remeber EventTypes are ObjectTypes! newEventType.NodeId = ExpandedNodeId.ToNodeId( ObjectTypeIds_TetrisEvents.TetrisLinesMadeEventType, SystemContext.NamespaceUris); // the fixed (in 'constants' defined) NodeId is used here! newEventType.SuperTypeId = ObjectTypeIds.BaseEventType; // our new EventType will inherit from BaseEventType newEventType.BrowseName = new QualifiedName(BrowseNames_TetrisEvents.TetrisLinesMadeEventType, NamespaceIndex); newEventType.DisplayName = new LocalizedText(BrowseNames_TetrisEvents.TetrisLinesMadeEventType); newEventType.IsAbstract = true; // events are NOT nodes in the Address Space (no instances can be made)s // Create the two Properties. // NrOfLinesMade: PropertyState <uint> nrOfLines = new PropertyState <uint>(newEventType); nrOfLines.NodeId = ExpandedNodeId.ToNodeId( VariableIds_TetrisEvents.TetrisLinesMadeEventType_NrOfLines, SystemContext.NamespaceUris); nrOfLines.BrowseName = new QualifiedName(BrowseNames_TetrisEvents.NrOfLines, NamespaceIndex); nrOfLines.DisplayName = new LocalizedText(BrowseNames_TetrisEvents.NrOfLines); nrOfLines.Description = new LocalizedText("An unsigned Integer representing the number of lines made in Tetris Game"); nrOfLines.ReferenceTypeId = ReferenceTypeIds.HasProperty; nrOfLines.TypeDefinitionId = VariableTypeIds.PropertyType; nrOfLines.DataType = DataTypeIds.UInt32; nrOfLines.ValueRank = ValueRanks.Scalar; // PointsScored: PropertyState <double> pointsScored = new PropertyState <double>(newEventType); pointsScored.NodeId = ExpandedNodeId.ToNodeId( VariableIds_TetrisEvents.TetrisLinesMadeEventType_PointsScored, SystemContext.NamespaceUris); pointsScored.BrowseName = new QualifiedName(BrowseNames_TetrisEvents.PointsScored, NamespaceIndex); pointsScored.DisplayName = new LocalizedText(BrowseNames_TetrisEvents.PointsScored); pointsScored.Description = new LocalizedText("A double representing the points scored when making 'NrOfLines' lines"); pointsScored.ReferenceTypeId = ReferenceTypeIds.HasProperty; pointsScored.TypeDefinitionId = VariableTypeIds.PropertyType; pointsScored.DataType = DataTypeIds.Double; pointsScored.ValueRank = ValueRanks.Scalar; // The constants defined in "TetrisEventsConstants.cs" were used above // for the creation of the NodeId's, BrowseNames and DisplayNames! //Add these two properties as children to the newEventType (= TetrisLinesMadeEventT:ype) newEventType.AddChild(pointsScored); newEventType.AddChild(nrOfLines); // ...And add newEventType (= TetrisLinesMadeEventType) it to the predefined nodes: AddPredefinedNode(SystemContext, newEventType); // will also add the new type to the Type Hierarchy! //--------------------------------------------------------------------------------------------- #endregion //------------------------ Initialize UpdateTimer--------------------------- m_UpdateTimer = new Timer(UpdateTimerCallback, null, 1000, 500); //-------------------------------------------------------------------------- } }