/// <summary> /// Adds a single hop path for all references for the node. /// </summary> private void AddSingleHopPaths(Node node, BrowsePathCollection pathsToTranslate) { ReferenceDescriptionCollection references = node.Handle as ReferenceDescriptionCollection; if (references == null) { return; } for (int ii = 0; ii < references.Count; ii++) { BrowsePath browsePath = new BrowsePath(); browsePath.StartingNode = node.NodeId; browsePath.Handle = node; RelativePathElement element = new RelativePathElement(); element.ReferenceTypeId = references[ii].ReferenceTypeId; element.IsInverse = !references[ii].IsForward; element.IncludeSubtypes = false; element.TargetName = references[ii].BrowseName; browsePath.RelativePath.Elements.Add(element); pathsToTranslate.Add(browsePath); } }
/// <summary> /// Parses a relative path formatted as a string. /// </summary> public static RelativePath Parse(string browsePath, ITypeTable typeTree) { if (typeTree == null) { throw new ArgumentNullException("typeTree"); } // parse the string. RelativePathFormatter formatter = RelativePathFormatter.Parse(browsePath); // convert the browse names to node ids. RelativePath relativePath = new RelativePath(); foreach (RelativePathFormatter.Element element in formatter.Elements) { RelativePathElement parsedElement = new RelativePathElement(); parsedElement.ReferenceTypeId = null; parsedElement.IsInverse = false; parsedElement.IncludeSubtypes = element.IncludeSubtypes; parsedElement.TargetName = element.TargetName; switch (element.ElementType) { case RelativePathFormatter.ElementType.AnyHierarchical: { parsedElement.ReferenceTypeId = ReferenceTypeIds.HierarchicalReferences; break; } case RelativePathFormatter.ElementType.AnyComponent: { parsedElement.ReferenceTypeId = ReferenceTypeIds.Aggregates; break; } case RelativePathFormatter.ElementType.ForwardReference: { parsedElement.ReferenceTypeId = typeTree.FindReferenceType(element.ReferenceTypeName); break; } case RelativePathFormatter.ElementType.InverseReference: { parsedElement.ReferenceTypeId = typeTree.FindReferenceType(element.ReferenceTypeName); parsedElement.IsInverse = true; break; } } if (NodeId.IsNull(parsedElement.ReferenceTypeId)) { throw ServiceResultException.Create( StatusCodes.BadSyntaxError, "Could not convert BrowseName to a ReferenceTypeId: {0}", element.ReferenceTypeName); } relativePath.Elements.Add(parsedElement); } return(relativePath); }
/// <summary> /// Creates a relative path to follow the forward reference type to find the specified browse name. /// </summary> public RelativePath(NodeId referenceTypeId, bool isInverse, bool includeSubtypes, QualifiedName browseName) { Initialize(); RelativePathElement element = new RelativePathElement(); element.ReferenceTypeId = referenceTypeId; element.IsInverse = isInverse; element.IncludeSubtypes = includeSubtypes; element.TargetName = browseName; m_elements.Add(element); }
/// <summary> /// Format relative path element information /// </summary> /// <param name="element"></param> /// <param name="context"></param> /// <returns></returns> private static string FormatRelativePathElement(RelativePathElement element, ServiceMessageContext context) { var value = ""; var writeReference = false; if (element.ReferenceTypeId == ReferenceTypeIds.HierarchicalReferences) { value += "/"; } else if (element.ReferenceTypeId == ReferenceTypeIds.Aggregates) { value += "."; } else if (element.ReferenceTypeId != ReferenceTypeIds.References) { value += "<"; writeReference = true; } if (element.IsInverse) { value += "!"; } if (!element.IncludeSubtypes) { value += "#"; } if (writeReference) { string reference = null; if (element.ReferenceTypeId.NamespaceIndex == 0 && element.ReferenceTypeId.Identifier is uint id) { TypeMaps.ReferenceTypes.Value.TryGetBrowseName(id, out reference); } if (string.IsNullOrEmpty(reference)) { reference = element.ReferenceTypeId.AsString(context); } // TODO: Escape <,>,/,:,&,. value += reference + ">"; } var target = element.TargetName.AsString(context); // TODO: Escape <,>,/,:,&,. value += target; return(value); }
/// <summary> /// Constructs an operand from a value. /// </summary> /// <param name="nodeId">The node identifier.</param> /// <param name="browsePath">The browse path.</param> public AttributeOperand( NodeId nodeId, QualifiedName browsePath) { m_nodeId = nodeId; m_attributeId = Attributes.Value; m_browsePath = new RelativePath(); RelativePathElement element = new RelativePathElement(); element.ReferenceTypeId = ReferenceTypeIds.Aggregates; element.IsInverse = false; element.IncludeSubtypes = true; element.TargetName = browsePath; m_browsePath.Elements.Add(element); }
/// <summary> /// Constructs an operand from a value. /// </summary> /// <param name="nodeId">The node identifier.</param> /// <param name="browsePaths">The browse paths.</param> public AttributeOperand( NodeId nodeId, IList <QualifiedName> browsePaths) { m_nodeId = nodeId; m_attributeId = Attributes.Value; m_browsePath = new RelativePath(); for (int ii = 0; ii < browsePaths.Count; ii++) { RelativePathElement element = new RelativePathElement(); element.ReferenceTypeId = ReferenceTypeIds.Aggregates; element.IsInverse = false; element.IncludeSubtypes = true; element.TargetName = browsePaths[ii]; m_browsePath.Elements.Add(element); } }
public virtual StatusCode HandleTranslateBrowsePathRequest( object session, BrowsePath path, List <BrowsePathTarget> res) { if (!this.AddressSpaceTable.TryGetValue(path.StartingNode, out Node node1) || !this.SessionHasPermissionToRead(session, path.StartingNode)) { return(StatusCode.BadNodeIdUnknown); } for (int index1 = 0; index1 < path.RelativePath.Length; ++index1) { RelativePathElement relativePathElement = path.RelativePath[index1]; ReferenceNode referenceNode = null; for (int index2 = 0; index2 < node1.References.Count; ++index2) { ReferenceNode reference = node1.References[index2]; if (relativePathElement.IsInverse == reference.IsInverse && (relativePathElement.IncludeSubtypes || reference.ReferenceType.Equals(relativePathElement.ReferenceTypeId)) && ((!relativePathElement.IncludeSubtypes || this.IsSubtypeOrEqual(reference.ReferenceType, relativePathElement.ReferenceTypeId)) && (this.AddressSpaceTable.TryGetValue(reference.Target, out Node node2) && this.SessionHasPermissionToRead(session, reference.Target) && node2.BrowseName.Equals(relativePathElement.TargetName)))) { referenceNode = node1.References[index2]; node1 = node2; break; } } if (referenceNode == null || node1 == null) { res.Add(new BrowsePathTarget() { Target = node1.Id, RemainingPathIndex = (uint)index1 }); return(StatusCode.BadNoMatch); } } res.Add(new BrowsePathTarget() { Target = node1.Id, RemainingPathIndex = (uint)path.RelativePath.Length }); return(StatusCode.Good); }
/// <summary> /// Initializes the object from a RelativePathElement /// </summary> public Element(RelativePathElement element, ITypeTable typeTree) { if (element == null) { throw new ArgumentNullException("element"); } if (typeTree == null) { throw new ArgumentNullException("typeTree"); } m_referenceTypeName = null; m_targetName = element.TargetName; m_elementType = RelativePathFormatter.ElementType.ForwardReference; m_includeSubtypes = element.IncludeSubtypes; if (!element.IsInverse && element.IncludeSubtypes) { if (element.ReferenceTypeId == ReferenceTypeIds.HierarchicalReferences) { m_elementType = RelativePathFormatter.ElementType.AnyHierarchical; } else if (element.ReferenceTypeId == ReferenceTypeIds.Aggregates) { m_elementType = RelativePathFormatter.ElementType.AnyComponent; } else { m_referenceTypeName = typeTree.FindReferenceTypeName(element.ReferenceTypeId); } } else { if (element.IsInverse) { m_elementType = RelativePathFormatter.ElementType.InverseReference; } m_referenceTypeName = typeTree.FindReferenceTypeName(element.ReferenceTypeId); } }
/// <summary> /// Constructs the browse path. /// </summary> /// <param name="nodeId">The node id.</param> /// <param name="hdaAttributeId">The hda attribute id.</param> /// <param name="browsePaths">The browse paths.</param> /// <returns></returns> private BrowsePath Construct(NodeId nodeId, uint hdaAttributeId, params string[] browsePaths) { BrowsePath browsePath = new BrowsePath(); browsePath.StartingNode = nodeId; browsePath.Handle = hdaAttributeId; for (int ii = 0; ii < browsePaths.Length; ii++) { RelativePathElement element = new RelativePathElement(); element.ReferenceTypeId = ReferenceTypeIds.HasChild; element.IsInverse = false; element.IncludeSubtypes = true; element.TargetName = browsePaths[ii]; browsePath.RelativePath.Elements.Add(element); } return(browsePath); }
/// <summary> /// Recursively collects the variables in a NodeState and returns a collection of BrowsePaths. /// </summary> public void GetBrowsePathFromNodeState( ISystemContext context, NodeId rootId, NodeState parent, RelativePath parentPath, BrowsePathCollection browsePaths) { List <BaseInstanceState> children = new List <BaseInstanceState>(); parent.GetChildren(context, children); for (int ii = 0; ii < children.Count; ii++) { BaseInstanceState child = children[ii]; BrowsePath browsePath = new BrowsePath(); browsePath.StartingNode = rootId; browsePath.Handle = child; if (parentPath != null) { browsePath.RelativePath.Elements.AddRange(parentPath.Elements); } RelativePathElement element = new RelativePathElement(); element.ReferenceTypeId = child.ReferenceTypeId; element.IsInverse = false; element.IncludeSubtypes = false; element.TargetName = child.BrowseName; browsePath.RelativePath.Elements.Add(element); if (child.NodeClass == NodeClass.Variable) { browsePaths.Add(browsePath); } GetBrowsePathFromNodeState(context, rootId, child, browsePath.RelativePath, browsePaths); } }
/// <summary> /// Returns the target of the specified browse path fragment(s). /// </summary> /// <remarks> /// If reference exists but the node manager does not know the browse name it must /// return the NodeId as an unresolvedTargetIds. The caller will try to check the /// browse name. /// </remarks> public virtual void TranslateBrowsePath( OperationContext context, object sourceHandle, RelativePathElement relativePath, IList<ExpandedNodeId> targetIds, IList<NodeId> unresolvedTargetIds) { ServerSystemContext systemContext = m_systemContext.Copy(context); IDictionary<NodeId,NodeState> operationCache = new NodeIdDictionary<NodeState>(); lock (Lock) { // verify that the node exists. NodeState source = IsHandleInNamespace(sourceHandle); if (source == null) { return; } // validate node. if (!ValidateNode(systemContext, source)) { return; } // get list of references that relative path. INodeBrowser browser = source.CreateBrowser( systemContext, null, relativePath.ReferenceTypeId, relativePath.IncludeSubtypes, (relativePath.IsInverse) ? BrowseDirection.Inverse : BrowseDirection.Forward, relativePath.TargetName, null, false); // check the browse names. try { for (IReference reference = browser.Next(); reference != null; reference = browser.Next()) { // ignore unknown external references. if (reference.TargetId.IsAbsolute) { continue; } NodeState target = null; // check for local reference. NodeStateReference referenceInfo = reference as NodeStateReference; if (referenceInfo != null) { target = referenceInfo.Target; } if (target == null) { NodeId targetId = (NodeId)reference.TargetId; // the target may be a reference to a node in another node manager. if (!IsNodeIdInNamespace(targetId)) { unresolvedTargetIds.Add((NodeId)reference.TargetId); continue; } // look up the target manually. target = GetManagerHandle(systemContext, targetId, operationCache) as NodeState; if (target == null) { continue; } } // check browse name. if (target.BrowseName == relativePath.TargetName) { targetIds.Add(reference.TargetId); } } } finally { browser.Dispose(); } } }
/// <summary> /// Finds an element identified by the path from the root. /// </summary> private AeBrowseElement Find(Session session, string itemId, AeBrowseElement root, Stack <string> names, bool isArea) { string browseText = null; BrowsePath browsePath = new BrowsePath(); browsePath.StartingNode = root.NodeId; while (names.Count > 0) { RelativePathElement path = new RelativePathElement(); path.ReferenceTypeId = Opc.Ua.ReferenceTypeIds.HasNotifier; path.IsInverse = false; path.IncludeSubtypes = true; // final hop can be HasEventSource for sources. if (!isArea && names.Count == 1) { path.ReferenceTypeId = Opc.Ua.ReferenceTypeIds.HasEventSource; } browseText = names.Pop(); path.TargetName = m_mapper.GetRemoteBrowseName(browseText); browsePath.RelativePath.Elements.Add(path); } BrowsePathCollection browsePaths = new BrowsePathCollection(); browsePaths.Add(browsePath); // make the call to the server. BrowsePathResultCollection results; DiagnosticInfoCollection diagnosticInfos; ResponseHeader responseHeader = session.TranslateBrowsePathsToNodeIds( null, browsePaths, out results, out diagnosticInfos); // ensure that the server returned valid results. Session.ValidateResponse(results, browsePaths); Session.ValidateDiagnosticInfos(diagnosticInfos, browsePaths); // check if the start node actually exists. if (StatusCode.IsBad(results[0].StatusCode)) { return(null); } // must be exact one target. if (results[0].Targets.Count != 1) { return(null); } // can't be an external reference. BrowsePathTarget target = results[0].Targets[0]; if (target.RemainingPathIndex != UInt32.MaxValue) { return(null); } // need to check if at the end of the tree. BrowseDescription nodeToBrowse = new BrowseDescription(); nodeToBrowse.NodeId = (NodeId)target.TargetId; nodeToBrowse.ReferenceTypeId = Opc.Ua.ReferenceTypeIds.HasEventSource; nodeToBrowse.BrowseDirection = BrowseDirection.Forward; nodeToBrowse.IncludeSubtypes = true; ReferenceDescriptionCollection children = ComAeUtils.Browse(session, nodeToBrowse, false); if (!isArea) { if (children != null && children.Count > 0) { return(null); } } else { if (children == null || children.Count == 0) { return(null); } } // construct the element. AeBrowseElement element = new AeBrowseElement(); element.NodeId = (NodeId)target.TargetId; element.ItemId = itemId; element.BrowseText = browseText; element.IsArea = isArea; return(element); }
/// <summary> /// Adds a single hop path for all references for the node. /// </summary> private void AddMultiHopPaths( Node node, Node baseNode, IList <RelativePathElement> basePath, BrowsePathCollection pathsToTranslate, int hops) { ReferenceDescriptionCollection references = node.Handle as ReferenceDescriptionCollection; if (references == null) { return; } for (int ii = 0; ii < references.Count; ii++) { ReferenceDescription reference = references[ii]; BrowsePath browsePath = new BrowsePath(); browsePath.StartingNode = baseNode.NodeId; browsePath.Handle = baseNode; if (basePath != null) { browsePath.RelativePath.Elements.AddRange(basePath); } RelativePathElement element = new RelativePathElement(); element.ReferenceTypeId = ReferenceTypeIds.NonHierarchicalReferences; element.IsInverse = !reference.IsForward; element.IncludeSubtypes = true; element.TargetName = reference.BrowseName; browsePath.RelativePath.Elements.Add(element); pathsToTranslate.Add(browsePath); // only follow forward heiarchical if (!Session.TypeTree.IsTypeOf(reference.ReferenceTypeId, ReferenceTypeIds.HierarchicalReferences)) { continue; } element.ReferenceTypeId = ReferenceTypeIds.HierarchicalReferences; // can't do anything with absolute or inverse references. if (!reference.IsForward || reference.NodeId.IsAbsolute) { continue; } // look up target if (browsePath.RelativePath.Elements.Count < hops) { Node target = null; if (!AvailableNodes.TryGetValue((NodeId)reference.NodeId, out target)) { continue; } AddMultiHopPaths(target, baseNode, browsePath.RelativePath.Elements, pathsToTranslate, hops); } } }
/// <summary> /// Recursively finds the targets of the specified path. /// </summary> private void GetTargets(Node start, IList <RelativePathElement> path, int index, BrowsePathResult result) { // check for invalid parameters. if (index >= path.Count) { return; } // look for list of references for node. ReferenceDescriptionCollection references = start.Handle as ReferenceDescriptionCollection; if (references == null || references.Count == 0) { return; } RelativePathElement element = path[index]; // each list of references. for (int ii = 0; ii < references.Count; ii++) { ReferenceDescription reference = references[ii]; // check for a reference match. if (element.IsInverse == reference.IsForward) { continue; } if (element.ReferenceTypeId != reference.ReferenceTypeId) { if (!element.IncludeSubtypes) { continue; } if (!Session.TypeTree.IsTypeOf(reference.ReferenceTypeId, element.ReferenceTypeId)) { continue; } } // check for a browse name match. if (element.TargetName != reference.BrowseName) { continue; } // check for end of list. if (index == path.Count - 1) { BrowsePathTarget item = new BrowsePathTarget(); item.TargetId = reference.NodeId; item.RemainingPathIndex = UInt32.MaxValue; result.Targets.Add(item); continue; } // check for external reference. if (reference.NodeId.IsAbsolute) { BrowsePathTarget item = new BrowsePathTarget(); item.TargetId = reference.NodeId; item.RemainingPathIndex = (uint)index + 1; result.Targets.Add(item); continue; } // check for targets. Node target = null; if (!AvailableNodes.TryGetValue((NodeId)reference.NodeId, out target)) { BrowsePathTarget item = new BrowsePathTarget(); item.TargetId = reference.NodeId; item.RemainingPathIndex = (uint)index + 1; result.Targets.Add(item); continue; } // recursively follow targets. GetTargets(target, path, index + 1, result); } }
/// <see cref="INodeManager.TranslateBrowsePath(OperationContext,object,RelativePathElement,IList{ExpandedNodeId},IList{NodeId})" /> public void TranslateBrowsePath( OperationContext context, object sourceHandle, RelativePathElement relativePath, IList<ExpandedNodeId> targetIds, IList<NodeId> unresolvedTargetIds) { if (sourceHandle == null) throw new ArgumentNullException("sourceHandle"); if (relativePath == null) throw new ArgumentNullException("relativePath"); if (targetIds == null) throw new ArgumentNullException("targetIds"); if (unresolvedTargetIds == null) throw new ArgumentNullException("unresolvedTargetIds"); // check for valid handle. ILocalNode source = sourceHandle as ILocalNode; if (source == null) { return; } lock(m_lock) { // find the references that meet the filter criteria. IList<IReference> references = source.References.Find( relativePath.ReferenceTypeId, relativePath.IsInverse, relativePath.IncludeSubtypes, m_server.TypeTree); // nothing more to do. if (references == null || references.Count == 0) { return; } // find targets with matching browse names. foreach (IReference reference in references) { INode target = GetLocalNode(reference.TargetId); // target is not known to the node manager. if (target == null) { // ignore unknown external references. if (reference.TargetId.IsAbsolute) { continue; } // caller must check the browse name. unresolvedTargetIds.Add((NodeId)reference.TargetId); continue; } // check browse name. if (target.BrowseName == relativePath.TargetName) { targetIds.Add(reference.TargetId); } } } }
/// <summary> /// Updates the list of references. /// </summary> private void UpdateArguments(Session session, NodeId nodeId) { ArgumentsLV.Items.Clear(); // need to fetch the node ids for the argument properties. BrowsePathCollection browsePaths = new BrowsePathCollection(); foreach (string browseName in new string[] { BrowseNames.InputArguments, BrowseNames.OutputArguments }) { BrowsePath browsePath = new BrowsePath(); browsePath.StartingNode = nodeId; browsePath.Handle = browseName; RelativePathElement element = new RelativePathElement(); element.ReferenceTypeId = ReferenceTypeIds.HasProperty; element.IsInverse = false; element.IncludeSubtypes = true; element.TargetName = browseName; browsePath.RelativePath.Elements.Add(element); browsePaths.Add(browsePath); } // translate property names. BrowsePathResultCollection results = null; DiagnosticInfoCollection diagnosticInfos = null; session.TranslateBrowsePathsToNodeIds( null, browsePaths, out results, out diagnosticInfos); ClientBase.ValidateResponse(results, browsePaths); ClientBase.ValidateDiagnosticInfos(diagnosticInfos, browsePaths); // create a list of values to read. ReadValueIdCollection valuesToRead = new ReadValueIdCollection(); for (int ii = 0; ii < results.Count; ii++) { if (StatusCode.IsBad(results[ii].StatusCode) || results[ii].Targets.Count <= 0) { continue; } ReadValueId valueToRead = new ReadValueId(); valueToRead.NodeId = (NodeId)results[ii].Targets[0].TargetId; valueToRead.AttributeId = Attributes.Value; valueToRead.Handle = browsePaths[ii].Handle; valuesToRead.Add(valueToRead); } // read the values. if (valuesToRead.Count > 0) { DataValueCollection values = null; session.Read( null, 0, TimestampsToReturn.Neither, valuesToRead, out values, out diagnosticInfos); ClientBase.ValidateResponse(results, valuesToRead); ClientBase.ValidateDiagnosticInfos(diagnosticInfos, valuesToRead); // update the list control. for (int ii = 0; ii < values.Count; ii++) { // all structures are wrapped in extension objects. ExtensionObject[] extensions = values[ii].GetValue <ExtensionObject[]>(null); if (extensions != null) { // convert to an argument structure. Argument[] arguments = (Argument[])ExtensionObject.ToArray(extensions, typeof(Argument)); UpdateList(session, arguments, (string)valuesToRead[ii].Handle); } } } // auto size the columns. for (int ii = 0; ii < ArgumentsLV.Columns.Count; ii++) { ArgumentsLV.Columns[ii].Width = -2; } }
/// <summary> /// Constructs the browse path. /// </summary> /// <param name="nodeId">The node id.</param> /// <param name="hdaAttributeId">The hda attribute id.</param> /// <param name="browsePaths">The browse paths.</param> /// <returns></returns> private BrowsePath Construct(NodeId nodeId, uint hdaAttributeId, params string[] browsePaths) { BrowsePath browsePath = new BrowsePath(); browsePath.StartingNode = nodeId; browsePath.Handle = hdaAttributeId; for (int ii = 0; ii < browsePaths.Length; ii++) { RelativePathElement element = new RelativePathElement(); element.ReferenceTypeId = ReferenceTypeIds.HasChild; element.IsInverse = false; element.IncludeSubtypes = true; element.TargetName = browsePaths[ii]; browsePath.RelativePath.Elements.Add(element); } return browsePath; }
/// <summary> /// Initializes the object from a RelativePathElement /// </summary> public Element(RelativePathElement element, ITypeTable typeTree) { if (element == null) throw new ArgumentNullException("element"); if (typeTree == null) throw new ArgumentNullException("typeTree"); m_referenceTypeName = null; m_targetName = element.TargetName; m_elementType = RelativePathFormatter.ElementType.ForwardReference; m_includeSubtypes = element.IncludeSubtypes; if (!element.IsInverse && element.IncludeSubtypes) { if (element.ReferenceTypeId == ReferenceTypeIds.HierarchicalReferences) { m_elementType = RelativePathFormatter.ElementType.AnyHierarchical; } else if (element.ReferenceTypeId == ReferenceTypeIds.Aggregates) { m_elementType = RelativePathFormatter.ElementType.AnyComponent; } else { m_referenceTypeName = typeTree.FindReferenceTypeName(element.ReferenceTypeId); } } else { if (element.IsInverse) { m_elementType = RelativePathFormatter.ElementType.InverseReference; } m_referenceTypeName = typeTree.FindReferenceTypeName(element.ReferenceTypeId); } }
/// <summary> /// Finds an element identified by the path from the root. /// </summary> private AeBrowseElement Find(Session session, string itemId, AeBrowseElement root, Stack<string> names, bool isArea) { string browseText = null; BrowsePath browsePath = new BrowsePath(); browsePath.StartingNode = root.NodeId; while (names.Count > 0) { RelativePathElement path = new RelativePathElement(); path.ReferenceTypeId = Opc.Ua.ReferenceTypeIds.HasNotifier; path.IsInverse = false; path.IncludeSubtypes = true; // final hop can be HasEventSource for sources. if (!isArea && names.Count == 1) { path.ReferenceTypeId = Opc.Ua.ReferenceTypeIds.HasEventSource; } browseText = names.Pop(); path.TargetName = m_mapper.GetRemoteBrowseName(browseText); browsePath.RelativePath.Elements.Add(path); } BrowsePathCollection browsePaths = new BrowsePathCollection(); browsePaths.Add(browsePath); // make the call to the server. BrowsePathResultCollection results; DiagnosticInfoCollection diagnosticInfos; ResponseHeader responseHeader = session.TranslateBrowsePathsToNodeIds( null, browsePaths, out results, out diagnosticInfos); // ensure that the server returned valid results. Session.ValidateResponse(results, browsePaths); Session.ValidateDiagnosticInfos(diagnosticInfos, browsePaths); // check if the start node actually exists. if (StatusCode.IsBad(results[0].StatusCode)) { return null; } // must be exact one target. if (results[0].Targets.Count != 1) { return null; } // can't be an external reference. BrowsePathTarget target = results[0].Targets[0]; if (target.RemainingPathIndex != UInt32.MaxValue) { return null; } // need to check if at the end of the tree. BrowseDescription nodeToBrowse = new BrowseDescription(); nodeToBrowse.NodeId = (NodeId)target.TargetId; nodeToBrowse.ReferenceTypeId = Opc.Ua.ReferenceTypeIds.HasEventSource; nodeToBrowse.BrowseDirection = BrowseDirection.Forward; nodeToBrowse.IncludeSubtypes = true; ReferenceDescriptionCollection children = ComAeUtils.Browse(session, nodeToBrowse, false); if (!isArea) { if (children != null && children.Count > 0) { return null; } } else { if (children == null || children.Count == 0) { return null; } } // construct the element. AeBrowseElement element = new AeBrowseElement(); element.NodeId = (NodeId)target.TargetId; element.ItemId = itemId; element.BrowseText = browseText; element.IsArea = isArea; return element; }
/// <summary> /// Reads the historical configuration for the node. /// </summary> private HistoricalDataConfigurationState ReadConfiguration() { // load the defaults for the historical configuration object. HistoricalDataConfigurationState configuration = new HistoricalDataConfigurationState(null); configuration.Definition = new PropertyState<string>(configuration); configuration.MaxTimeInterval = new PropertyState<double>(configuration); configuration.MinTimeInterval = new PropertyState<double>(configuration); configuration.ExceptionDeviation = new PropertyState<double>(configuration); configuration.ExceptionDeviationFormat = new PropertyState<ExceptionDeviationFormat>(configuration); configuration.StartOfArchive = new PropertyState<DateTime>(configuration); configuration.StartOfOnlineArchive = new PropertyState<DateTime>(configuration); configuration.Create( m_session.SystemContext, null, Opc.Ua.BrowseNames.HAConfiguration, null, false); // get the browse paths to query. RelativePathElement element = new RelativePathElement(); element.ReferenceTypeId = Opc.Ua.ReferenceTypeIds.HasHistoricalConfiguration; element.IsInverse = false; element.IncludeSubtypes = false; element.TargetName = Opc.Ua.BrowseNames.HAConfiguration; RelativePath relativePath = new RelativePath(); relativePath.Elements.Add(element); BrowsePathCollection pathsToTranslate = new BrowsePathCollection(); GetBrowsePathFromNodeState( m_session.SystemContext, m_nodeId, configuration, relativePath, pathsToTranslate); // translate browse paths. BrowsePathResultCollection results = null; DiagnosticInfoCollection diagnosticInfos = null; m_session.TranslateBrowsePathsToNodeIds( null, pathsToTranslate, out results, out diagnosticInfos); ClientBase.ValidateResponse(results, pathsToTranslate); ClientBase.ValidateDiagnosticInfos(diagnosticInfos, pathsToTranslate); // build list of values to read. ReadValueIdCollection valuesToRead = new ReadValueIdCollection(); for (int ii = 0; ii < pathsToTranslate.Count; ii++) { BaseVariableState variable = (BaseVariableState)pathsToTranslate[ii].Handle; variable.Value = null; variable.StatusCode = StatusCodes.BadNotSupported; if (StatusCode.IsBad(results[ii].StatusCode) || results[ii].Targets.Count == 0) { continue; } if (results[ii].Targets[0].RemainingPathIndex == UInt32.MaxValue && !results[ii].Targets[0].TargetId.IsAbsolute) { variable.NodeId = (NodeId)results[ii].Targets[0].TargetId; ReadValueId valueToRead = new ReadValueId(); valueToRead.NodeId = variable.NodeId; valueToRead.AttributeId = Attributes.Value; valueToRead.Handle = variable; valuesToRead.Add(valueToRead); } } // read the values. if (valuesToRead.Count > 0) { DataValueCollection values = null; m_session.Read( null, 0, TimestampsToReturn.Neither, valuesToRead, out values, out diagnosticInfos); ClientBase.ValidateResponse(values, valuesToRead); ClientBase.ValidateDiagnosticInfos(diagnosticInfos, valuesToRead); for (int ii = 0; ii < valuesToRead.Count; ii++) { BaseVariableState variable = (BaseVariableState)valuesToRead[ii].Handle; variable.WrappedValue = values[ii].WrappedValue; variable.StatusCode = values[ii].StatusCode; } } return configuration; }
/// <summary> /// Recursively collects the variables in a NodeState and returns a collection of BrowsePaths. /// </summary> public void GetBrowsePathFromNodeState( ISystemContext context, NodeId rootId, NodeState parent, RelativePath parentPath, BrowsePathCollection browsePaths) { List<BaseInstanceState> children = new List<BaseInstanceState>(); parent.GetChildren(context, children); for (int ii = 0; ii < children.Count; ii++) { BaseInstanceState child = children[ii]; BrowsePath browsePath = new BrowsePath(); browsePath.StartingNode = rootId; browsePath.Handle = child; if (parentPath != null) { browsePath.RelativePath.Elements.AddRange(parentPath.Elements); } RelativePathElement element = new RelativePathElement(); element.ReferenceTypeId = child.ReferenceTypeId; element.IsInverse = false; element.IncludeSubtypes = false; element.TargetName = child.BrowseName; browsePath.RelativePath.Elements.Add(element); if (child.NodeClass == NodeClass.Variable) { browsePaths.Add(browsePath); } GetBrowsePathFromNodeState(context, rootId, child, browsePath.RelativePath, browsePaths); } }
/// <summary> /// Updates the EUInfo for the items. /// </summary> /// <param name="group">The group.</param> /// <param name="items">The items. Null entries are ignored.</param> public void UpdateItemEuInfo( ComDaGroup group, IList<ComDaGroupItem> items) { // get the session to use for the operation. Session session = m_session; if (session == null) { throw ComUtils.CreateComException(ResultIds.E_FAIL); } // build list of properties that need to be read. BrowsePathCollection browsePaths = new BrowsePathCollection(); for (int ii = 0; ii < items.Count; ii++) { ComDaGroupItem item = (ComDaGroupItem)items[ii]; // ignore invalid items or items which have already checked their EU type. if (item == null || item.EuType >= 0) { continue; } BrowsePath browsePath = new BrowsePath(); browsePath.StartingNode = item.NodeId; RelativePathElement element = new RelativePathElement(); element.ReferenceTypeId = ReferenceTypeIds.HasProperty; element.IsInverse = false; element.IncludeSubtypes = false; element.TargetName = Opc.Ua.BrowseNames.EURange; browsePath.RelativePath.Elements.Add(element); browsePath.Handle = item; browsePaths.Add(browsePath); browsePath = new BrowsePath(); browsePath.StartingNode = item.NodeId; element = new RelativePathElement(); element.ReferenceTypeId = ReferenceTypeIds.HasProperty; element.IsInverse = false; element.IncludeSubtypes = false; element.TargetName = Opc.Ua.BrowseNames.EnumStrings; browsePath.RelativePath.Elements.Add(element); browsePath.Handle = item; browsePaths.Add(browsePath); } // check if nothing to do. if (browsePaths.Count == 0) { return; } // translate browse paths. BrowsePathResultCollection results = null; DiagnosticInfoCollection diagnosticInfos = null; try { session.TranslateBrowsePathsToNodeIds( null, browsePaths, out results, out diagnosticInfos); ClientBase.ValidateResponse(results, browsePaths); ClientBase.ValidateDiagnosticInfos(diagnosticInfos, browsePaths); } catch (Exception) { for (int ii = 0; ii < browsePaths.Count; ii++) { ComDaGroupItem item = (ComDaGroupItem)browsePaths[ii].Handle; item.EuType = 0; } return; } // build list of properties that need to be read. ReadValueIdCollection propertiesToRead = new ReadValueIdCollection(); for (int ii = 0; ii < results.Count; ii++) { ComDaGroupItem item = (ComDaGroupItem)browsePaths[ii].Handle; BrowsePathResult result = results[ii]; if (StatusCode.IsBad(result.StatusCode)) { if (item.EuType < 0 && result.StatusCode == StatusCodes.BadNoMatch) { item.EuType = (int)OpcRcw.Da.OPCEUTYPE.OPC_NOENUM; } continue; } if (result.Targets.Count == 0 || result.Targets[0].TargetId.IsAbsolute) { if (item.EuType < 0) { item.EuType = (int)OpcRcw.Da.OPCEUTYPE.OPC_NOENUM; } continue; } ReadValueId propertyToRead = new ReadValueId(); propertyToRead.NodeId = (NodeId)result.Targets[0].TargetId; propertyToRead.AttributeId = Attributes.Value; propertyToRead.Handle = item; propertiesToRead.Add(propertyToRead); if (browsePaths[ii].RelativePath.Elements[0].TargetName.Name == Opc.Ua.BrowseNames.EURange) { item.EuType = (int)OpcRcw.Da.OPCEUTYPE.OPC_ANALOG; } else { item.EuType = (int)OpcRcw.Da.OPCEUTYPE.OPC_ENUMERATED; } } // check if nothing to do. if (propertiesToRead.Count == 0) { return; } // read attribute values from the server. DataValueCollection values = null; try { session.Read( null, 0, TimestampsToReturn.Neither, propertiesToRead, out values, out diagnosticInfos); ClientBase.ValidateResponse(values, propertiesToRead); ClientBase.ValidateDiagnosticInfos(diagnosticInfos, propertiesToRead); } catch (Exception) { for (int ii = 0; ii < propertiesToRead.Count; ii++) { ComDaGroupItem item = (ComDaGroupItem)propertiesToRead[ii].Handle; item.EuType = 0; } return; } // process results. for (int ii = 0; ii < values.Count; ii++) { ComDaGroupItem item = (ComDaGroupItem)propertiesToRead[ii].Handle; if (StatusCode.IsBad(values[ii].StatusCode)) { item.EuType = 0; continue; } if (item.EuType == (int)OpcRcw.Da.OPCEUTYPE.OPC_ANALOG) { Range range = (Range)values[ii].GetValue<Range>(null); if (range == null) { item.EuType = 0; continue; } item.EuInfo = new double[] { range.Low, range.High }; continue; } if (item.EuType == (int)OpcRcw.Da.OPCEUTYPE.OPC_ENUMERATED) { LocalizedText[] texts = (LocalizedText[])values[ii].GetValue<LocalizedText[]>(null); if (texts == null) { item.EuType = 0; continue; } string[] strings = new string[texts.Length]; for (int jj = 0; jj < strings.Length; jj++) { if (!LocalizedText.IsNullOrEmpty(texts[jj])) { strings[jj] = texts[jj].Text; } } item.EuInfo = strings; continue; } } }
/// <summary> /// Follows the browse path and returns any targets found. /// </summary> public void TranslateBrowsePath( BrowsePath request, BrowsePathResult result, DiagnosticInfo diagnosticInfo) { lock (m_lock) { // find the starting node. Node source = m_nodes.Find(request.StartingNode); if (source == null) { result.StatusCode = new StatusCode(StatusCodes.BadNodeIdUnknown); return; } // check if there is nothing to do. if (request.RelativePath.Elements == null || request.RelativePath.Elements.Count == 0) { result.StatusCode = new StatusCode(StatusCodes.BadNothingToDo); return; } result.Targets = new ListOfBrowsePathTarget(); Node current = source; // follow each element in the browse path. for (int ii = 0; ii < request.RelativePath.Elements.Count; ii++) { RelativePathElement element = request.RelativePath.Elements[ii]; bool found = false; // need to find any matching reference. foreach (ReferenceNode reference in current.References) { // inverse is a quick check - do that first. if (reference.IsInverse != element.IsInverse) { continue; } // check for reference type matches. if (reference.ReferenceTypeId != element.ReferenceTypeId) { if (!element.IncludeSubtypes) { continue; } if (!IsTypeOf(reference.ReferenceTypeId, element.ReferenceTypeId)) { continue; } } // The UA type model requires that the browse names of all targets of hierarchial references // be unique within a parent. This means most browse paths will point to no more than one node. // However, instances are allowed to add additional nodes with duplicate browse names. If the server // allows this it must keep track of the child that matches the type model and return it as the // first target. // need to find the target to check the browse name. Node target = m_nodes.Find(reference.TargetId); if (target != null) { if (element.TargetName == target.BrowseName) { found = true; current = target; break; } } } if (found) { // check if the complete path has been followed. if (ii == request.RelativePath.Elements.Count - 1) { BrowsePathTarget item = new BrowsePathTarget(); item.TargetId = new ExpandedNodeId(current.NodeId); item.RemainingPathIndex = UInt32.MaxValue; result.Targets.Add(item); } } } } }
/// <summary> /// Parses a relative path formatted as a string. /// </summary> public static RelativePath Parse(string browsePath, ITypeTable typeTree) { if (typeTree == null) throw new ArgumentNullException("typeTree"); // parse the string. RelativePathFormatter formatter = RelativePathFormatter.Parse(browsePath); // convert the browse names to node ids. RelativePath relativePath = new RelativePath(); foreach (RelativePathFormatter.Element element in formatter.Elements) { RelativePathElement parsedElement = new RelativePathElement(); parsedElement.ReferenceTypeId = null; parsedElement.IsInverse = false; parsedElement.IncludeSubtypes = element.IncludeSubtypes; parsedElement.TargetName = element.TargetName; switch (element.ElementType) { case RelativePathFormatter.ElementType.AnyHierarchical: { parsedElement.ReferenceTypeId = ReferenceTypeIds.HierarchicalReferences; break; } case RelativePathFormatter.ElementType.AnyComponent: { parsedElement.ReferenceTypeId = ReferenceTypeIds.Aggregates; break; } case RelativePathFormatter.ElementType.ForwardReference: { parsedElement.ReferenceTypeId = typeTree.FindReferenceType(element.ReferenceTypeName); break; } case RelativePathFormatter.ElementType.InverseReference: { parsedElement.ReferenceTypeId = typeTree.FindReferenceType(element.ReferenceTypeName); parsedElement.IsInverse = true; break; } } if (NodeId.IsNull(parsedElement.ReferenceTypeId)) { throw ServiceResultException.Create( StatusCodes.BadSyntaxError, "Could not convert BrowseName to a ReferenceTypeId: {0}", element.ReferenceTypeName); } relativePath.Elements.Add(parsedElement); } return relativePath; }
/// <summary> /// Convert to path element object /// </summary> /// <param name="element"></param> /// <param name="context"></param> /// <returns></returns> private static RelativePathElement ParsePathElement(string element, ServiceMessageContext context) { if (string.IsNullOrEmpty(element)) { throw new ArgumentNullException(nameof(element)); } var pathElement = new RelativePathElement { IncludeSubtypes = true, IsInverse = false }; // // Parse relative path reference information // This should allow // - "targeturi" == "/targeturi" // - ".targeturi" // - "!.parenturi" // - "!/parenturi" // - "<!#uri>parenturi" // var index = 0; var exit = false; var parseReference = false; while (index < element.Length && !exit) { switch (element[index]) { case '<': if (pathElement.ReferenceTypeId == null) { parseReference = true; break; } throw new FormatException("Reference type set."); case '!': pathElement.IsInverse = true; break; case '#': pathElement.IncludeSubtypes = false; break; case '/': if (pathElement.ReferenceTypeId == null && !parseReference) { pathElement.ReferenceTypeId = ReferenceTypeIds.HierarchicalReferences; break; } throw new FormatException("Reference type set."); case '.': if (pathElement.ReferenceTypeId == null && !parseReference) { pathElement.ReferenceTypeId = ReferenceTypeIds.Aggregates; break; } throw new FormatException("Reference type set."); default: if (element[index] == '&') { index++; } if (pathElement.ReferenceTypeId == null && !parseReference) { // Set to all references pathElement.ReferenceTypeId = ReferenceTypeIds.References; } exit = true; break; } index++; } index--; if (parseReference) { var to = index; while (to < element.Length) { if (element[to] == '>' && element[to - 1] != '&') { break; } to++; if (to == element.Length) { throw new FormatException( "Reference path starts in < but does not end in >"); } } var reference = element.Substring(index, to - index); // TODO: Deescape &<, &>, &/, &., &:, && index = to + 1; pathElement.ReferenceTypeId = reference.ToNodeId(context); if (NodeId.IsNull(pathElement.ReferenceTypeId)) { if (TypeMaps.ReferenceTypes.Value.TryGetIdentifier(reference, out var id)) { pathElement.ReferenceTypeId = id; } } } var target = element.Substring(index); // TODO: Deescape &<, &>, &/, &., &:, && if (string.IsNullOrEmpty(target)) { throw new FormatException("Bad target name is empty"); } pathElement.TargetName = target.ToQualifiedName(context); return(pathElement); }
/// <summary> /// Constructs an operand from a value. /// </summary> /// <param name="nodeId">The node identifier.</param> /// <param name="browsePaths">The browse paths.</param> public AttributeOperand( NodeId nodeId, IList<QualifiedName> browsePaths) { m_nodeId = nodeId; m_attributeId = Attributes.Value; m_browsePath = new RelativePath(); for (int ii = 0; ii < browsePaths.Count; ii++) { RelativePathElement element = new RelativePathElement(); element.ReferenceTypeId = ReferenceTypeIds.Aggregates; element.IsInverse = false; element.IncludeSubtypes = true; element.TargetName = browsePaths[ii]; m_browsePath.Elements.Add(element); } }
/// <summary> /// Adds a single hop path for all references for the node. /// </summary> private void AddMultiHopPaths( Node node, Node baseNode, IList<RelativePathElement> basePath, BrowsePathCollection pathsToTranslate, int hops) { ReferenceDescriptionCollection references = node.Handle as ReferenceDescriptionCollection; if (references == null) { return; } for (int ii = 0; ii < references.Count; ii++) { ReferenceDescription reference = references[ii]; BrowsePath browsePath = new BrowsePath(); browsePath.StartingNode = baseNode.NodeId; browsePath.Handle = baseNode; if (basePath != null) { browsePath.RelativePath.Elements.AddRange(basePath); } RelativePathElement element = new RelativePathElement(); element.ReferenceTypeId = ReferenceTypeIds.NonHierarchicalReferences; element.IsInverse = !reference.IsForward; element.IncludeSubtypes = true; element.TargetName = reference.BrowseName; browsePath.RelativePath.Elements.Add(element); pathsToTranslate.Add(browsePath); // only follow forward heiarchical if (!Session.TypeTree.IsTypeOf(reference.ReferenceTypeId, ReferenceTypeIds.HierarchicalReferences)) { continue; } element.ReferenceTypeId = ReferenceTypeIds.HierarchicalReferences; // can't do anything with absolute or inverse references. if (!reference.IsForward || reference.NodeId.IsAbsolute) { continue; } // look up target if (browsePath.RelativePath.Elements.Count < hops) { Node target = null; if (!AvailableNodes.TryGetValue((NodeId)reference.NodeId, out target)) { continue; } AddMultiHopPaths(target, baseNode, browsePath.RelativePath.Elements, pathsToTranslate, hops); } } }
/// <summary> /// Updates the EUInfo for the items. /// </summary> /// <param name="group">The group.</param> /// <param name="items">The items. Null entries are ignored.</param> public void UpdateItemEuInfo( ComDaGroup group, IList <ComDaGroupItem> items) { // get the session to use for the operation. Session session = m_session; if (session == null) { throw ComUtils.CreateComException(ResultIds.E_FAIL); } // build list of properties that need to be read. BrowsePathCollection browsePaths = new BrowsePathCollection(); for (int ii = 0; ii < items.Count; ii++) { ComDaGroupItem item = (ComDaGroupItem)items[ii]; // ignore invalid items or items which have already checked their EU type. if (item == null || item.EuType >= 0) { continue; } BrowsePath browsePath = new BrowsePath(); browsePath.StartingNode = item.NodeId; RelativePathElement element = new RelativePathElement(); element.ReferenceTypeId = ReferenceTypeIds.HasProperty; element.IsInverse = false; element.IncludeSubtypes = false; element.TargetName = Opc.Ua.BrowseNames.EURange; browsePath.RelativePath.Elements.Add(element); browsePath.Handle = item; browsePaths.Add(browsePath); browsePath = new BrowsePath(); browsePath.StartingNode = item.NodeId; element = new RelativePathElement(); element.ReferenceTypeId = ReferenceTypeIds.HasProperty; element.IsInverse = false; element.IncludeSubtypes = false; element.TargetName = Opc.Ua.BrowseNames.EnumStrings; browsePath.RelativePath.Elements.Add(element); browsePath.Handle = item; browsePaths.Add(browsePath); } // check if nothing to do. if (browsePaths.Count == 0) { return; } // translate browse paths. BrowsePathResultCollection results = null; DiagnosticInfoCollection diagnosticInfos = null; try { session.TranslateBrowsePathsToNodeIds( null, browsePaths, out results, out diagnosticInfos); ClientBase.ValidateResponse(results, browsePaths); ClientBase.ValidateDiagnosticInfos(diagnosticInfos, browsePaths); } catch (Exception) { for (int ii = 0; ii < browsePaths.Count; ii++) { ComDaGroupItem item = (ComDaGroupItem)browsePaths[ii].Handle; item.EuType = 0; } return; } // build list of properties that need to be read. ReadValueIdCollection propertiesToRead = new ReadValueIdCollection(); for (int ii = 0; ii < results.Count; ii++) { ComDaGroupItem item = (ComDaGroupItem)browsePaths[ii].Handle; BrowsePathResult result = results[ii]; if (StatusCode.IsBad(result.StatusCode)) { if (item.EuType < 0 && result.StatusCode == StatusCodes.BadNoMatch) { item.EuType = (int)OpcRcw.Da.OPCEUTYPE.OPC_NOENUM; } continue; } if (result.Targets.Count == 0 || result.Targets[0].TargetId.IsAbsolute) { if (item.EuType < 0) { item.EuType = (int)OpcRcw.Da.OPCEUTYPE.OPC_NOENUM; } continue; } ReadValueId propertyToRead = new ReadValueId(); propertyToRead.NodeId = (NodeId)result.Targets[0].TargetId; propertyToRead.AttributeId = Attributes.Value; propertyToRead.Handle = item; propertiesToRead.Add(propertyToRead); if (browsePaths[ii].RelativePath.Elements[0].TargetName.Name == Opc.Ua.BrowseNames.EURange) { item.EuType = (int)OpcRcw.Da.OPCEUTYPE.OPC_ANALOG; } else { item.EuType = (int)OpcRcw.Da.OPCEUTYPE.OPC_ENUMERATED; } } // check if nothing to do. if (propertiesToRead.Count == 0) { return; } // read attribute values from the server. DataValueCollection values = null; try { session.Read( null, 0, TimestampsToReturn.Neither, propertiesToRead, out values, out diagnosticInfos); ClientBase.ValidateResponse(values, propertiesToRead); ClientBase.ValidateDiagnosticInfos(diagnosticInfos, propertiesToRead); } catch (Exception) { for (int ii = 0; ii < propertiesToRead.Count; ii++) { ComDaGroupItem item = (ComDaGroupItem)propertiesToRead[ii].Handle; item.EuType = 0; } return; } // process results. for (int ii = 0; ii < values.Count; ii++) { ComDaGroupItem item = (ComDaGroupItem)propertiesToRead[ii].Handle; if (StatusCode.IsBad(values[ii].StatusCode)) { item.EuType = 0; continue; } if (item.EuType == (int)OpcRcw.Da.OPCEUTYPE.OPC_ANALOG) { Range range = (Range)values[ii].GetValue <Range>(null); if (range == null) { item.EuType = 0; continue; } item.EuInfo = new double[] { range.Low, range.High }; continue; } if (item.EuType == (int)OpcRcw.Da.OPCEUTYPE.OPC_ENUMERATED) { LocalizedText[] texts = (LocalizedText[])values[ii].GetValue <LocalizedText[]>(null); if (texts == null) { item.EuType = 0; continue; } string[] strings = new string[texts.Length]; for (int jj = 0; jj < strings.Length; jj++) { if (!LocalizedText.IsNullOrEmpty(texts[jj])) { strings[jj] = texts[jj].Text; } } item.EuInfo = strings; continue; } } }
/// <summary> /// Updates the list of references. /// </summary> private void UpdateArguments(Session session, NodeId nodeId) { ArgumentsLV.Items.Clear(); // need to fetch the node ids for the argument properties. BrowsePathCollection browsePaths = new BrowsePathCollection(); foreach (string browseName in new string[] { BrowseNames.InputArguments, BrowseNames.OutputArguments }) { BrowsePath browsePath = new BrowsePath(); browsePath.StartingNode = nodeId; browsePath.Handle = browseName; RelativePathElement element = new RelativePathElement(); element.ReferenceTypeId = ReferenceTypeIds.HasProperty; element.IsInverse = false; element.IncludeSubtypes = true; element.TargetName = browseName; browsePath.RelativePath.Elements.Add(element); browsePaths.Add(browsePath); } // translate property names. BrowsePathResultCollection results = null; DiagnosticInfoCollection diagnosticInfos = null; session.TranslateBrowsePathsToNodeIds( null, browsePaths, out results, out diagnosticInfos); ClientBase.ValidateResponse(results, browsePaths); ClientBase.ValidateDiagnosticInfos(diagnosticInfos, browsePaths); // create a list of values to read. ReadValueIdCollection valuesToRead = new ReadValueIdCollection(); for (int ii = 0; ii < results.Count; ii++) { if (StatusCode.IsBad(results[ii].StatusCode) || results[ii].Targets.Count <= 0) { continue; } ReadValueId valueToRead = new ReadValueId(); valueToRead.NodeId = (NodeId)results[ii].Targets[0].TargetId; valueToRead.AttributeId = Attributes.Value; valueToRead.Handle = browsePaths[ii].Handle; valuesToRead.Add(valueToRead); } // read the values. if (valuesToRead.Count > 0) { DataValueCollection values = null; session.Read( null, 0, TimestampsToReturn.Neither, valuesToRead, out values, out diagnosticInfos); ClientBase.ValidateResponse(results, valuesToRead); ClientBase.ValidateDiagnosticInfos(diagnosticInfos, valuesToRead); // update the list control. for (int ii = 0; ii < values.Count; ii++) { // all structures are wrapped in extension objects. ExtensionObject[] extensions = values[ii].GetValue<ExtensionObject[]>(null); if (extensions != null) { // convert to an argument structure. Argument[] arguments = (Argument[])ExtensionObject.ToArray(extensions, typeof(Argument)); UpdateList(session, arguments, (string)valuesToRead[ii].Handle); } } } // auto size the columns. for (int ii = 0; ii < ArgumentsLV.Columns.Count; ii++) { ArgumentsLV.Columns[ii].Width = -2; } }