/// <summary> /// Validates the nodes and writes the value to the underlying system. /// </summary> /// <param name="context">The context.</param> /// <param name="nodesToWrite">The nodes to write.</param> /// <param name="errors">The errors.</param> /// <param name="nodesToValidate">The nodes to validate.</param> /// <param name="cache">The cache.</param> protected override void Write( ServerSystemContext context, IList <WriteValue> nodesToWrite, IList <ServiceResult> errors, List <NodeHandle> nodesToValidate, IDictionary <NodeId, NodeState> cache) { ComDaClientManager system = (ComDaClientManager)this.SystemContext.SystemHandle; ComDaClient client = system.SelectClient((ServerSystemContext)SystemContext, false); WriteRequestCollection requests = new WriteRequestCollection(); // validates the nodes and queues an write requests. for (int ii = 0; ii < nodesToValidate.Count; ii++) { NodeHandle handle = nodesToValidate[ii]; lock (Lock) { // validate node. NodeState source = ValidateNode(context, handle, cache); if (source == null) { continue; } // determine if request can be sent to the server. bool queued = false; WriteValue nodeToWrite = nodesToWrite[handle.Index]; errors[handle.Index] = requests.Add(source, nodeToWrite, handle.Index, out queued); if (queued) { continue; } // write the attribute value. errors[handle.Index] = source.WriteAttribute( context, nodeToWrite.AttributeId, nodeToWrite.ParsedIndexRange, nodeToWrite.Value); // updates to source finished - report changes to monitored items. source.ClearChangeMasks(context, false); } } // write to the server. client.Write(requests); // get the results from the requests sent to the server. for (int ii = 0; ii < requests.Count; ii++) { WriteRequest request = requests[ii]; errors[request.Index] = request.GetResult(); } }
/// <summary> /// Creates an empty group. /// </summary> /// <param name="server">The server that the group belongs to.</param> /// <param name="callbacksRequired">if set to <c>true</c> if the group will received callbacks.</param> public ComDaGroup(ComDaClient server, bool callbacksRequired) { m_server = server; m_clientHandle = Utils.IncrementIdentifier(ref m_groupCounter); m_serverHandle = 0; m_items = new List <GroupItem>(); if (callbacksRequired) { m_monitoredItems = new Dictionary <int, DataChangeInfo>(); } // Utils.Trace("GROUP {0}", m_clientHandle); }
/// <summary> /// Handles a method call. /// </summary> private ServiceResult DoGenerateRandomValues( ISystemContext context, MethodState method, IList <object> inputArguments, IList <object> outputArguments) { ComDaClientManager system = (ComDaClientManager)this.SystemContext.SystemHandle; ComDaClient client = system.SelectClient((ServerSystemContext)context, false); Opc.Ua.Test.DataGenerator generator = new Opc.Ua.Test.DataGenerator(null); IDaElementBrowser browser = client.CreateBrowser((string)method.Handle); // create write requests. WriteRequestCollection requests = new WriteRequestCollection(); try { for (DaElement element = browser.Next(); element != null; element = browser.Next()) { if (element.ElementType == DaElementType.Branch) { continue; } // generate a random value of the correct data tyoe. bool isArray = false; NodeId dataTypeId = ComUtils.GetDataTypeId(element.DataType, out isArray); object value = generator.GetRandom( dataTypeId, (isArray)?ValueRanks.OneDimension:ValueRanks.Scalar, null, context.TypeTable); // create a request. requests.Add(new Opc.Ua.Com.Client.WriteRequest(element.ItemId, new DataValue(new Variant(value)), 0)); } } finally { browser.Dispose(); } // write values. client.Write(requests); return(ServiceResult.Good); }
/// <summary> /// Called when a batch of monitored items has been created. /// </summary> protected override void OnCreateMonitoredItemsComplete(ServerSystemContext context, IList <IMonitoredItem> monitoredItems) { ComDaClientManager system = (ComDaClientManager)this.SystemContext.SystemHandle; ComDaClient client = system.SelectClient(context, false); // use locale for session to find a subscription manager. SubscribeRequestManager manager = null; if (!m_subscriptionManagers.TryGetValue(client.Key, out manager)) { m_subscriptionManagers[client.Key] = manager = new SubscribeRequestManager(context, client, 1000); } manager.CreateItems(context, monitoredItems); for (int ii = 0; ii < monitoredItems.Count; ii++) { m_monitoredItems[monitoredItems[ii].Id] = manager; } }
/// <summary> /// Called when a batch of monitored items has been deleted. /// </summary> protected override void OnDeleteMonitoredItemsComplete(ServerSystemContext context, IList <IMonitoredItem> monitoredItems) { ComDaClientManager system = (ComDaClientManager)this.SystemContext.SystemHandle; ComDaClient client = system.SelectClient(context, false); // sort monitored items by the locale id used to create them. Dictionary <string, List <IMonitoredItem> > monitoredItemsByLocaleId = new Dictionary <string, List <IMonitoredItem> >(); for (int ii = 0; ii < monitoredItems.Count; ii++) { // look up the manager that was previously used to create the monitor item. SubscribeRequestManager manager = null; if (!m_monitoredItems.TryGetValue(monitoredItems[ii].Id, out manager)) { manager = m_subscriptionManagers[client.Key]; } // add monitored item to a list of items for the locale of the manager. List <IMonitoredItem> subset = null; if (!monitoredItemsByLocaleId.TryGetValue(manager.Key, out subset)) { monitoredItemsByLocaleId[manager.Key] = subset = new List <IMonitoredItem>(); } subset.Add(monitoredItems[ii]); } // delete the items. foreach (KeyValuePair <string, List <IMonitoredItem> > entry in monitoredItemsByLocaleId) { SubscribeRequestManager manager = null; if (m_subscriptionManagers.TryGetValue(entry.Key, out manager)) { manager.DeleteItems(context, entry.Value); } } }
/// <summary> /// Updates the status node. /// </summary> protected override bool UpdateStatus() { // get the status from the server. ComDaClient client = DefaultClient; OPCSERVERSTATUS?status = client.GetStatus(); // check the client has been abandoned. if (!Object.ReferenceEquals(client, DefaultClient)) { return(false); } // update the server status. lock (StatusNodeLock) { StatusNode.ServerUrl.Value = Configuration.ServerUrl; if (status != null) { StatusNode.SetStatusCode(DefaultSystemContext, StatusCodes.Good, DateTime.UtcNow); StatusNode.ServerState.Value = Utils.Format("{0}", status.Value.dwServerState); StatusNode.CurrentTime.Value = ComUtils.GetDateTime(status.Value.ftCurrentTime); StatusNode.LastUpdateTime.Value = ComUtils.GetDateTime(status.Value.ftLastUpdateTime); StatusNode.StartTime.Value = ComUtils.GetDateTime(status.Value.ftStartTime); StatusNode.VendorInfo.Value = status.Value.szVendorInfo; StatusNode.SoftwareVersion.Value = Utils.Format("{0}.{1}.{2}", status.Value.wMajorVersion, status.Value.wMinorVersion, status.Value.wBuildNumber); } else { StatusNode.SetStatusCode(DefaultSystemContext, StatusCodes.BadOutOfService, DateTime.UtcNow); } StatusNode.ClearChangeMasks(DefaultSystemContext, true); return(status != null); } }
/// <summary> /// Validates the nodes and reads the values from the underlying source. /// </summary> /// <param name="context">The context.</param> /// <param name="nodesToRead">The nodes to read.</param> /// <param name="values">The values.</param> /// <param name="errors">The errors.</param> /// <param name="nodesToValidate">The nodes to validate.</param> /// <param name="cache">The cache.</param> protected override void Read( ServerSystemContext context, IList <ReadValueId> nodesToRead, IList <DataValue> values, IList <ServiceResult> errors, List <NodeHandle> nodesToValidate, IDictionary <NodeId, NodeState> cache) { ComDaClientManager system = (ComDaClientManager)this.SystemContext.SystemHandle; ComDaClient client = system.SelectClient((ServerSystemContext)SystemContext, false); ReadRequestCollection requests = new ReadRequestCollection(); for (int ii = 0; ii < nodesToValidate.Count; ii++) { NodeHandle handle = nodesToValidate[ii]; lock (Lock) { NodeState source = ValidateNode(context, handle, cache); if (source == null) { continue; } DataValue value = values[handle.Index]; ReadValueId nodeToRead = nodesToRead[handle.Index]; // determine if request can be sent to the server. bool queued = false; errors[handle.Index] = requests.Add(source, nodeToRead, value, out queued); if (queued) { continue; } // read built-in metadata. errors[handle.Index] = source.ReadAttribute( context, nodeToRead.AttributeId, nodeToRead.ParsedIndexRange, nodeToRead.DataEncoding, value); } } // read the values from the server. client.Read(requests); // extract the values from the results. for (int ii = 0; ii < nodesToValidate.Count; ii++) { NodeHandle handle = nodesToValidate[ii]; DataValue value = values[handle.Index]; ReadValueId nodeToRead = nodesToRead[handle.Index]; lock (Lock) { if (!requests.HasResult(nodeToRead)) { continue; } errors[handle.Index] = requests.GetResult(context, handle.Node, nodeToRead, value, context.DiagnosticsMask); } } }
/// <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. DaParsedNodeId parsedNodeId = handle.ParsedNodeId as DaParsedNodeId; if (parsedNodeId == null) { return(null); } NodeState root = null; DaElement element = null; ComDaClient client = m_system.SelectClient(context, false); // validate a branch or item. if (parsedNodeId.RootType == DaModelUtils.DaElement) { element = client.FindElement(parsedNodeId.RootId); // branch does not exist. if (element == null) { return(null); } // create a temporary object to use for the operation. root = DaModelUtils.ConstructElement(context, element, NamespaceIndex); root.Handle = element; AddAdditionalElementReferences(SystemContext, root); } // validate an property. else if (parsedNodeId.RootType == DaModelUtils.DaProperty) { element = client.FindElement(parsedNodeId.RootId); // branch does not exist. if (element == null) { return(null); } // validate the property. DaProperty property = client.FindProperty(parsedNodeId.RootId, parsedNodeId.PropertyId); // property does not exist. if (property == null) { return(null); } // create a temporary object to use for the operation. root = DaModelUtils.ConstructProperty(context, element.ItemId, property, NamespaceIndex); root.Handle = property; AddAdditionalElementReferences(SystemContext, root); } // unknown root type. else { return(null); } // all done if no components to validate. if (String.IsNullOrEmpty(parsedNodeId.ComponentPath)) { handle.Validated = true; handle.Node = target = root; return(handle.Node); } // validate component. NodeState component = root.FindChildBySymbolicName(context, parsedNodeId.ComponentPath); // component does not exist. if (component == null) { return(null); } // found a valid component. handle.Validated = true; handle.Node = target = component; return(handle.Node); } finally { // store the node in the cache to optimize subsequent lookups. if (cache != null) { cache.Add(handle.NodeId, target); } } }
/// <summary> /// Initializes a new instance of the <see cref="Da20ElementBrowser"/> class. /// </summary> /// <param name="client">The client.</param> /// <param name="itemId">The item id.</param> public Da20ElementBrowser( ComDaClient client, string itemId) { m_client = client; m_itemId = itemId; m_branches = false; }
/// <summary> /// Applies any changes to the groups. /// </summary> public void ApplyGroupChanges(ComDaClient client) { List<ComDaGroup> groups = null; List<SubscribeItemRequest> items = null; lock (m_lock) { items = new List<SubscribeItemRequest>(m_subscribedItems.Values); // modify or remove items. for (int ii = 0; ii < items.Count; ii++) { SubscribeItemRequest request = items[ii]; // remove unused requests. if (request.MonitoredItems.Count == 0) { if (request.Group != null && request.GroupItem != null) { request.Group.RemoveItem(request.GroupItem); } Remove(request); continue; } } // add any new items to groups. for (int ii = 0; ii < items.Count; ii++) { SubscribeItemRequest request = items[ii]; if (!request.Changed) { continue; } UpdateGroup(client, request); } groups = new List<ComDaGroup>(m_groups.Count); // update group on the server. for (int ii = 0; ii < m_groups.Count; ii++) { if (m_groups[ii].ApplyChanges()) { groups.Add(m_groups[ii]); } else { m_groups[ii].Delete(); } } m_groups = groups; // update request. for (int ii = 0; ii < items.Count; ii++) { if (items[ii].Changed) { items[ii].ChangesComplete(); } } // modify or remove items. List<SubscribePropertyRequest> properties = new List<SubscribePropertyRequest>(m_subscribedProperties.Values); for (int ii = 0; ii < properties.Count; ii++) { SubscribePropertyRequest request = properties[ii]; // remove unused requests. if (request.MonitoredItems == null || request.MonitoredItems.Count == 0) { Remove(request); continue; } request.ChangesComplete(m_propertySamplingInterval); } // check if the property scanner needs to be stopped/started. if (m_propertyScanTimer == null) { if (m_subscribedProperties.Count > 0) { m_propertyScanTimer = new Timer(OnScanProperties, null, 0, m_propertySamplingInterval); } } else { if (m_subscribedProperties.Count == 0) { m_propertyScanTimer.Dispose(); m_propertyScanTimer = null; } } } }
/// <summary> /// Assigns a request to a group. /// </summary> /// <param name="client">The client.</param> /// <param name="request">The request.</param> public void UpdateGroup(ComDaClient client, SubscribeItemRequest request) { lock (m_lock) { // check for empty request. if (request.MonitoredItems.Count == 0) { return; } request.Update(); // check if existing group can be used. if (request.Group != null) { if (request.Group.ModifyItem(request.GroupItem, request.SamplingInterval, request.Deadband, request.Active)) { if (request.GroupItem.Active != request.Active) { request.GroupItem.Active = request.Active; request.GroupItem.ActiveChanged = true; } request.Group.SetMonitoredItems(request.GroupItem, request.MonitoredItems.ToArray()); return; } } // clear link to existing group. request.Group = null; request.GroupItem = null; // assign to an existing group. for (int ii = 0; ii < m_groups.Count; ii++) { ComDaGroup group = m_groups[ii]; request.GroupItem = group.CreateItem(request.ItemId, request.SamplingInterval, request.Deadband, request.Active); if (request.GroupItem != null) { request.Group = group; request.Group.SetMonitoredItems(request.GroupItem, request.MonitoredItems.ToArray()); return; } } // create a new group. request.Group = new ComDaGroup(client, true); request.GroupItem = request.Group.CreateItem(request.ItemId, request.SamplingInterval, request.Deadband, request.Active); request.Group.SetMonitoredItems(request.GroupItem, request.MonitoredItems.ToArray()); m_groups.Add(request.Group); } }
/// <summary> /// Initializes the next stage of browsing. /// </summary> private void NextStage() { ComDaClientManager system = (ComDaClientManager)this.SystemContext.SystemHandle; ComDaClient client = system.SelectClient((ServerSystemContext)SystemContext, false); // determine which stage is next based on the reference types requested. for (Stage next = m_stage + 1; next <= Stage.Done; next++) { if (next == Stage.Children) { if (IsRequired(ReferenceTypeIds.Organizes, false)) { m_stage = next; break; } } else if (next == Stage.Properties) { if (IsRequired(ReferenceTypeIds.HasProperty, false)) { m_stage = next; break; } } else if (next == Stage.Parents) { if (IsRequired(ReferenceTypeIds.Organizes, true)) { m_stage = next; break; } } else if (next == Stage.Done) { m_stage = next; break; } } m_position = 0; // start enumerating branches. if (m_stage == Stage.Children) { m_browser = client.CreateBrowser(m_itemId); return; } // start enumerating properties. if (m_stage == Stage.Properties) { m_properties = client.ReadAvailableProperties(m_itemId, true); m_position = 0; return; } // start enumerating parents. if (m_stage == Stage.Parents) { m_parentId = client.FindElementParentId(m_itemId); return; } // all done. }
/// <summary> /// Returns the next child. /// </summary> private NodeStateReference NextChild(Stage stage) { ComDaClientManager system = (ComDaClientManager)this.SystemContext.SystemHandle; ComDaClient client = system.SelectClient((ServerSystemContext)SystemContext, false); DaElement element = null; if (stage == Stage.Children) { if (m_browser == null) { return(null); } element = m_browser.Next(); if (element == null) { return(null); } // construct the node. NodeState node = DaModelUtils.ConstructElement(SystemContext, element, m_namespaceIndex); // return the reference. return(new NodeStateReference(ReferenceTypeIds.Organizes, false, node)); } if (stage == Stage.Properties) { if (m_properties == null) { return(null); } for (int ii = m_position; ii < m_properties.Length; ii++) { if (m_properties[ii].PropertyId <= PropertyIds.TimeZone) { continue; } m_position = ii + 1; // construct the node. NodeState node = DaModelUtils.ConstructProperty(SystemContext, m_itemId, m_properties[ii], m_namespaceIndex); // return the reference. return(new NodeStateReference(ReferenceTypeIds.HasProperty, false, node)); } // all done. return(null); } if (stage == Stage.Parents) { if (m_parentId != null) { NodeId parentId = DaModelUtils.ConstructIdForDaElement(m_parentId, -1, m_namespaceIndex); m_parentId = null; return(new NodeStateReference(ReferenceTypeIds.Organizes, true, parentId)); } } return(null); }