/// <summary> /// Initializes a memory tag for a buffer. /// </summary> /// <param name="parent">The buffer that owns the tag.</param> /// <param name="offet">The offset of the tag address in the memory buffer.</param> public MemoryTagState(MemoryBufferState parent, uint offet) : base(parent) { // these objects are created an discarded during each operation. // the metadata is derived from the parameters passed to constructors. NodeId = new NodeId(Utils.Format("{0}[{1}]", parent.SymbolicName, offet), parent.NodeId.NamespaceIndex); BrowseName = new QualifiedName(Utils.Format("{1:X8}", parent.SymbolicName, offet), parent.TypeDefinitionId.NamespaceIndex); DisplayName = BrowseName.Name; Description = null; WriteMask = AttributeWriteMask.None; UserWriteMask = AttributeWriteMask.None; ReferenceTypeId = ReferenceTypeIds.HasComponent; TypeDefinitionId = new NodeId(VariableTypes.MemoryTagType, parent.TypeDefinitionId.NamespaceIndex); ModellingRuleId = null; NumericId = offet; DataType = new NodeId((uint)parent.ElementType); ValueRank = ValueRanks.Scalar; ArrayDimensions = null; AccessLevel = AccessLevels.CurrentReadOrWrite; UserAccessLevel = AccessLevels.CurrentReadOrWrite; MinimumSamplingInterval = parent.MaximumScanRate; Historizing = false; // re-direct read and write operations to the parent. OnReadValue = parent.ReadTagValue; OnWriteValue = parent.WriteTagValue; Offset = offet; }
/// <summary> /// Initializes a memory tag for a buffer. /// </summary> /// <param name="parent">The buffer that owns the tag.</param> /// <param name="offet">The offset of the tag address in the memory buffer.</param> public MemoryTagState(MemoryBufferState parent, uint offet) : base(parent) { // these objects are created an discarded during each operation. // the metadata is derived from the parameters passed to constructors. NodeId = new NodeId(Utils.Format("{0}[{1}]", parent.SymbolicName, offet), parent.NodeId.NamespaceIndex); BrowseName = new QualifiedName(Utils.Format("{1:X8}", parent.SymbolicName, offet), parent.TypeDefinitionId.NamespaceIndex); DisplayName = BrowseName.Name; Description = null; WriteMask = AttributeWriteMask.None; UserWriteMask = AttributeWriteMask.None; ReferenceTypeId = Opc.Ua.ReferenceTypeIds.HasComponent; TypeDefinitionId = new NodeId(VariableTypes.MemoryTagType, parent.TypeDefinitionId.NamespaceIndex); ModellingRuleId = null; NumericId = offet; DataType = new NodeId((uint)parent.ElementType); ValueRank = ValueRanks.Scalar; ArrayDimensions = null; AccessLevel = AccessLevels.CurrentReadOrWrite; UserAccessLevel = AccessLevels.CurrentReadOrWrite; MinimumSamplingInterval = parent.MaximumScanRate; Historizing = false; // re-direct read and write operations to the parent. OnReadValue = parent.ReadTagValue; OnWriteValue = parent.WriteTagValue; m_offset = offet; }
/// <summary> /// Deletes a monitored item. /// </summary> protected override ServiceResult DeleteMonitoredItem( ISystemContext context, IMonitoredItem monitoredItem, out bool processed) { processed = false; // check for valid handle. MemoryBufferState buffer = monitoredItem.ManagerHandle as MemoryBufferState; if (buffer == null) { return(base.DeleteMonitoredItem( context, monitoredItem, out processed)); } // owned by this node manager. processed = true; // get the monitored item. MemoryBufferMonitoredItem datachangeItem = monitoredItem as MemoryBufferMonitoredItem; if (datachangeItem == null) { return(StatusCodes.BadMonitoredItemIdInvalid); } // delete the item. buffer.DeleteItem(datachangeItem); return(ServiceResult.Good); }
/// <summary> /// Changes the monitoring mode for an item. /// </summary> protected override ServiceResult SetMonitoringMode( ISystemContext context, IMonitoredItem monitoredItem, MonitoringMode monitoringMode, out bool processed) { processed = false; // check for valid handle. MemoryBufferState buffer = monitoredItem.ManagerHandle as MemoryBufferState; if (buffer == null) { return(base.SetMonitoringMode( context, monitoredItem, monitoringMode, out processed)); } // owned by this node manager. processed = true; // get the monitored item. MemoryBufferMonitoredItem datachangeItem = monitoredItem as MemoryBufferMonitoredItem; if (datachangeItem == null) { return(StatusCodes.BadMonitoredItemIdInvalid); } // delete the item. MonitoringMode previousMode = datachangeItem.SetMonitoringMode(monitoringMode); // need to provide an immediate update after enabling. if (previousMode == MonitoringMode.Disabled && monitoringMode != MonitoringMode.Disabled) { DataValue initialValue = new DataValue(); initialValue.Value = null; initialValue.ServerTimestamp = DateTime.UtcNow; initialValue.SourceTimestamp = DateTime.MinValue; initialValue.StatusCode = StatusCodes.Good; MemoryTagState tag = new MemoryTagState(buffer, datachangeItem.Offset); ServiceResult error = tag.ReadAttribute( context, datachangeItem.AttributeId, NumericRange.Empty, null, initialValue); datachangeItem.QueueValue(initialValue, error); } return(ServiceResult.Good); }
/// <summary> /// Modifies the parameters for a monitored item. /// </summary> protected override ServiceResult ModifyMonitoredItem( ISystemContext context, DiagnosticsMasks diagnosticsMasks, TimestampsToReturn timestampsToReturn, IMonitoredItem monitoredItem, MonitoredItemModifyRequest itemToModify, out MonitoringFilterResult filterError) { filterError = null; // check for valid handle. MemoryBufferState buffer = monitoredItem.ManagerHandle as MemoryBufferState; if (buffer == null) { return(base.ModifyMonitoredItem( context, diagnosticsMasks, timestampsToReturn, monitoredItem, itemToModify, out filterError)); } // owned by this node manager. itemToModify.Processed = true; // get the monitored item. MemoryBufferMonitoredItem datachangeItem = monitoredItem as MemoryBufferMonitoredItem; if (datachangeItem == null) { return(StatusCodes.BadMonitoredItemIdInvalid); } // validate parameters. MonitoringParameters parameters = itemToModify.RequestedParameters; // no filters supported at this time. MonitoringFilter filter = (MonitoringFilter)ExtensionObject.ToEncodeable(parameters.Filter); if (filter != null) { return(StatusCodes.BadFilterNotAllowed); } // modify the monitored item parameters. ServiceResult error = datachangeItem.Modify( diagnosticsMasks, timestampsToReturn, itemToModify.RequestedParameters.ClientHandle, itemToModify.RequestedParameters.SamplingInterval); return(ServiceResult.Good); }
/// <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) { base.CreateAddressSpace(externalReferences); // create the nodes from configuration. ushort namespaceIndex = Server.NamespaceUris.GetIndexOrAppend(Namespaces.MemoryBuffer); BaseInstanceState root = (BaseInstanceState)FindPredefinedNode( new NodeId(Objects.MemoryBuffers, namespaceIndex), typeof(BaseInstanceState)); // create the nodes from configuration. namespaceIndex = Server.NamespaceUris.GetIndexOrAppend(Namespaces.MemoryBuffer + "/Instance"); if (m_configuration != null && m_configuration.Buffers != null) { for (int ii = 0; ii < m_configuration.Buffers.Count; ii++) { MemoryBufferInstance instance = m_configuration.Buffers[ii]; // create a new buffer. MemoryBufferState bufferNode = new MemoryBufferState(SystemContext, instance); // assign node ids. bufferNode.Create( SystemContext, new NodeId(bufferNode.SymbolicName, namespaceIndex), new QualifiedName(bufferNode.SymbolicName, namespaceIndex), null, true); bufferNode.CreateBuffer(instance.DataType, instance.TagCount); bufferNode.InitializeMonitoring(Server, this); // save the buffers for easy look up later. m_buffers[bufferNode.SymbolicName] = bufferNode; // link to root. root.AddChild(bufferNode); } } } }
/// <summary> /// Creates a new browser object with a set of filters. /// </summary> public MemoryBufferBrowser( ISystemContext context, ViewDescription view, NodeId referenceType, bool includeSubtypes, BrowseDirection browseDirection, QualifiedName browseName, IEnumerable<IReference> additionalReferences, bool internalOnly, MemoryBufferState buffer) : base( context, view, referenceType, includeSubtypes, browseDirection, browseName, additionalReferences, internalOnly) { m_buffer = buffer; m_stage = Stage.Begin; }
/// <summary> /// Creates a new browser object with a set of filters. /// </summary> public MemoryBufferBrowser( ISystemContext context, ViewDescription view, NodeId referenceType, bool includeSubtypes, BrowseDirection browseDirection, QualifiedName browseName, IEnumerable <IReference> additionalReferences, bool internalOnly, MemoryBufferState buffer) : base( context, view, referenceType, includeSubtypes, browseDirection, browseName, additionalReferences, internalOnly) { m_buffer = buffer; m_stage = Stage.Begin; }
/// <summary> /// Creates a new set of monitored items for a set of variables. /// </summary> /// <remarks> /// This method only handles data change subscriptions. Event subscriptions are created by the SDK. /// </remarks> protected override ServiceResult CreateMonitoredItem( ISystemContext context, NodeState source, uint subscriptionId, double publishingInterval, DiagnosticsMasks diagnosticsMasks, TimestampsToReturn timestampsToReturn, MonitoredItemCreateRequest itemToCreate, ref long globalIdCounter, out MonitoringFilterResult filterError, out IMonitoredItem monitoredItem) { filterError = null; monitoredItem = null; MemoryTagState tag = source as MemoryTagState; // use default behavoir for non-tag sources. if (tag == null) { return(base.CreateMonitoredItem( context, source, subscriptionId, publishingInterval, diagnosticsMasks, timestampsToReturn, itemToCreate, ref globalIdCounter, out filterError, out monitoredItem)); } // validate parameters. MonitoringParameters parameters = itemToCreate.RequestedParameters; // no filters supported at this time. MonitoringFilter filter = (MonitoringFilter)ExtensionObject.ToEncodeable(parameters.Filter); if (filter != null) { return(StatusCodes.BadFilterNotAllowed); } // index range not supported. if (itemToCreate.ItemToMonitor.ParsedIndexRange != NumericRange.Empty) { return(StatusCodes.BadIndexRangeInvalid); } // data encoding not supported. if (!QualifiedName.IsNull(itemToCreate.ItemToMonitor.DataEncoding)) { return(StatusCodes.BadDataEncodingInvalid); } // read initial value. DataValue initialValue = new DataValue(); initialValue.Value = null; initialValue.ServerTimestamp = DateTime.UtcNow; initialValue.SourceTimestamp = DateTime.MinValue; initialValue.StatusCode = StatusCodes.Good; ServiceResult error = source.ReadAttribute( context, itemToCreate.ItemToMonitor.AttributeId, itemToCreate.ItemToMonitor.ParsedIndexRange, itemToCreate.ItemToMonitor.DataEncoding, initialValue); if (ServiceResult.IsBad(error)) { return(error); } // get the monitored node for the containing buffer. MemoryBufferState buffer = tag.Parent as MemoryBufferState; if (buffer == null) { return(StatusCodes.BadInternalError); } // create a globally unique identifier. uint monitoredItemId = Utils.IncrementIdentifier(ref globalIdCounter); // determine the sampling interval. double samplingInterval = itemToCreate.RequestedParameters.SamplingInterval; if (samplingInterval < 0) { samplingInterval = publishingInterval; } // create the item. MemoryBufferMonitoredItem datachangeItem = buffer.CreateDataChangeItem( context as ServerSystemContext, tag, subscriptionId, monitoredItemId, itemToCreate.ItemToMonitor, diagnosticsMasks, timestampsToReturn, itemToCreate.MonitoringMode, itemToCreate.RequestedParameters.ClientHandle, samplingInterval); /* * // create the item. * MemoryBufferMonitoredItem datachangeItem = buffer.CreateDataChangeItem( * context, * tag, * monitoredItemId, * itemToCreate.ItemToMonitor.AttributeId, * diagnosticsMasks, * timestampsToReturn, * itemToCreate.MonitoringMode, * itemToCreate.RequestedParameters.ClientHandle, * samplingInterval); */ // report the initial value. datachangeItem.QueueValue(initialValue, null); // update monitored item list. monitoredItem = datachangeItem; return(ServiceResult.Good); }
/// <summary> /// Returns a unique handle for the node. /// </summary> /// <remarks> /// This must efficiently determine whether the node belongs to the node manager. If it does belong to /// NodeManager it should return a handle that does not require the NodeId to be validated again when /// the handle is passed into other methods such as 'Read' or 'Write'. /// </remarks> protected override object GetManagerHandle(ISystemContext context, NodeId nodeId, IDictionary <NodeId, NodeState> cache) { lock (Lock) { if (!IsNodeIdInNamespace(nodeId)) { return(null); } string id = nodeId.Identifier as string; if (id != null) { // check for a reference to the buffer. MemoryBufferState buffer = null; if (m_buffers.TryGetValue(id, out buffer)) { return(buffer); } // tag ids have the syntax <bufferName>[<address>] if (id[id.Length - 1] != ']') { return(null); } int index = id.IndexOf('['); if (index == -1) { return(null); } string bufferName = id.Substring(0, index); // verify the buffer. if (!m_buffers.TryGetValue(bufferName, out buffer)) { return(null); } // validate the address. string offsetText = id.Substring(index + 1, id.Length - index - 2); for (int ii = 0; ii < offsetText.Length; ii++) { if (!Char.IsDigit(offsetText[ii])) { return(null); } } // check range on offset. uint offset = Convert.ToUInt32(offsetText); if (offset >= buffer.SizeInBytes.Value) { return(null); } // the tags contain all of the metadata required to support the UA // operations and pointers to functions in the buffer object that // allow the value to be accessed. These tags are ephemeral and are // discarded after the operation completes. This design pattern allows // the server to expose potentially millions of UA nodes without // creating millions of objects that reside in memory. return(new MemoryTagState(buffer, offset)); } return(base.GetManagerHandle(context, nodeId, cache)); } }
/// <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) { base.CreateAddressSpace(externalReferences); // create the nodes from configuration. ushort namespaceIndex = Server.NamespaceUris.GetIndexOrAppend(Namespaces.MemoryBuffer); BaseInstanceState root = (BaseInstanceState)FindPredefinedNode( new NodeId(Objects.MemoryBuffers, namespaceIndex), typeof(BaseInstanceState)); // create the nodes from configuration. namespaceIndex = Server.NamespaceUris.GetIndexOrAppend(Namespaces.MemoryBuffer + "/Instance"); if (m_configuration != null && m_configuration.Buffers != null) { for (int ii = 0; ii < m_configuration.Buffers.Count; ii++) { MemoryBufferInstance instance = m_configuration.Buffers[ii]; // create a new buffer. MemoryBufferState bufferNode = new MemoryBufferState(SystemContext, instance); // assign node ids. bufferNode.Create( SystemContext, new NodeId(bufferNode.SymbolicName, namespaceIndex), new QualifiedName(bufferNode.SymbolicName, namespaceIndex), null, true); bufferNode.CreateBuffer(instance.DataType, instance.TagCount); bufferNode.InitializeMonitoring(Server, this); // save the buffers for easy look up later. m_buffers[bufferNode.SymbolicName] = bufferNode; // link to root. root.AddChild(bufferNode); } } } }