/// <summary> /// Creates a new area. /// </summary> private BaseObjectState CreateArea(SystemContext context, BaseObjectState platforms, string areaName) { FolderState area = new FolderState(null); area.NodeId = new NodeId(areaName, NamespaceIndex); area.BrowseName = new QualifiedName(areaName, NamespaceIndex); area.DisplayName = area.BrowseName.Name; area.EventNotifier = EventNotifiers.SubscribeToEvents | EventNotifiers.HistoryRead | EventNotifiers.HistoryWrite; area.TypeDefinitionId = Opc.Ua.ObjectTypeIds.FolderType; platforms.AddNotifier(SystemContext, Opc.Ua.ReferenceTypeIds.HasNotifier, false, area); area.AddNotifier(SystemContext, Opc.Ua.ReferenceTypeIds.HasNotifier, true, platforms); AddPredefinedNode(SystemContext, area); return(area); }
/// <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); #region Task #A1 - Create Root Folder // create the root folder. FolderState root = new FolderState(null); root.NodeId = GenerateNodeId(); root.BrowseName = new QualifiedName("Root", NamespaceIndex); root.DisplayName = root.BrowseName.Name; root.TypeDefinitionId = ObjectTypeIds.FolderType; // ensure root can be found via the server object. IList <IReference> references = null; if (!externalReferences.TryGetValue(ObjectIds.ObjectsFolder, out references)) { externalReferences[ObjectIds.ObjectsFolder] = references = new List <IReference>(); } root.AddReference(ReferenceTypeIds.Organizes, true, ObjectIds.ObjectsFolder); references.Add(new NodeStateReference(ReferenceTypeIds.Organizes, false, root.NodeId)); // save the node for later lookup. AddPredefinedNode(SystemContext, root); #endregion #region Task #A2 - Create Object Instance with a Property // create the folder object. BaseObjectState instance = new BaseObjectState(null); instance.NodeId = GenerateNodeId(); instance.BrowseName = new QualifiedName("Object", NamespaceIndex); instance.DisplayName = instance.BrowseName.Name; instance.TypeDefinitionId = ObjectTypeIds.BaseObjectType; // create a losely coupled relationship with the root object. root.AddReference(ReferenceTypeIds.Organizes, false, instance.NodeId); instance.AddReference(ReferenceTypeIds.Organizes, true, root.NodeId); // create a property. PropertyState <int> property = new PropertyState <int>(instance); property.NodeId = GenerateNodeId(); property.BrowseName = new QualifiedName("Property", NamespaceIndex); property.DisplayName = property.BrowseName.Name; property.TypeDefinitionId = VariableTypeIds.PropertyType; property.DataType = DataTypeIds.Int32; property.ValueRank = ValueRanks.Scalar; property.MinimumSamplingInterval = MinimumSamplingIntervals.Continuous; property.AccessLevel = AccessLevels.CurrentReadOrWrite; property.UserAccessLevel = AccessLevels.CurrentReadOrWrite; property.Historizing = false; property.ReferenceTypeId = ReferenceTypeIds.HasProperty; // create a property that is tightly coupled. instance.AddChild(property); // save the node for later lookup (all tightly coupled children are added with this call). AddPredefinedNode(SystemContext, instance); #endregion #region Task #A3 - Create a Variable using the Built-in Type Model // create the variable. AnalogItemState <double> variable = new AnalogItemState <double>(instance); // add optional properties. variable.InstrumentRange = new PropertyState <Range>(variable); // instantiate based on the type model. assigns ids automatically using SystemContext.NodeIdFactory variable.Create( SystemContext, GenerateNodeId(), new QualifiedName("Variable", NamespaceIndex), null, true); // set default values. variable.EURange.Value = new Range(90, 10); variable.InstrumentRange.Value = new Range(100, 0); // tightly coupled. instance.AddChild(variable); // need to add it manually since its parent was already added. AddPredefinedNode(SystemContext, variable); #endregion #region Task #A4 - Add Dynamic Behavoir by Updating In-Memory Nodes m_property = property; m_simulationTimer = new Timer(DoSimulation, null, 1000, 1000); #endregion #region Task #A5 - Add Support for External Nodes // External nodes are nodes that reference an entity which stored elsewhere. // These nodes use no memory in the server unless they are accessed. // The NodeId is a string that is used to create the external node on demand. root.AddReference(ReferenceTypeIds.Organizes, false, CreateNodeId("Alpha")); root.AddReference(ReferenceTypeIds.Organizes, false, CreateNodeId("Omega")); #endregion #region Task #A7 - Add Support for Method MethodState method = new MethodState(instance); method.NodeId = GenerateNodeId(); method.BrowseName = new QualifiedName("Method", NamespaceIndex); method.DisplayName = method.BrowseName.Name; method.Executable = true; method.UserExecutable = true; method.ReferenceTypeId = ReferenceTypeIds.HasComponent; instance.AddChild(method); // create the input arguments. PropertyState <Argument[]> inputArguments = new PropertyState <Argument[]>(method); inputArguments.NodeId = GenerateNodeId(); inputArguments.BrowseName = new QualifiedName(BrowseNames.InputArguments); inputArguments.DisplayName = inputArguments.BrowseName.Name; inputArguments.TypeDefinitionId = VariableTypeIds.PropertyType; inputArguments.DataType = DataTypeIds.Argument; inputArguments.ValueRank = ValueRanks.OneDimension; inputArguments.MinimumSamplingInterval = MinimumSamplingIntervals.Continuous; inputArguments.AccessLevel = AccessLevels.CurrentRead; inputArguments.UserAccessLevel = AccessLevels.CurrentRead; inputArguments.Historizing = false; inputArguments.ReferenceTypeId = ReferenceTypeIds.HasProperty; inputArguments.Value = new Argument[] { new Argument() { Name = "CurrentCount", Description = "The current count.", DataType = DataTypeIds.Int32, ValueRank = ValueRanks.Scalar } }; method.InputArguments = inputArguments; // create the output arguments. PropertyState <Argument[]> outputArguments = new PropertyState <Argument[]>(method); outputArguments.NodeId = GenerateNodeId(); outputArguments.BrowseName = new QualifiedName(BrowseNames.OutputArguments); outputArguments.DisplayName = outputArguments.BrowseName.Name; outputArguments.TypeDefinitionId = VariableTypeIds.PropertyType; outputArguments.DataType = DataTypeIds.Argument; outputArguments.ValueRank = ValueRanks.OneDimension; outputArguments.MinimumSamplingInterval = MinimumSamplingIntervals.Continuous; outputArguments.AccessLevel = AccessLevels.CurrentRead; outputArguments.UserAccessLevel = AccessLevels.CurrentRead; outputArguments.Historizing = false; outputArguments.ReferenceTypeId = ReferenceTypeIds.HasProperty; outputArguments.Value = new Argument[] { new Argument() { Name = "NewCount", Description = "The new count.", DataType = DataTypeIds.Int32, ValueRank = ValueRanks.Scalar } }; method.OutputArguments = outputArguments; // save the node for later lookup (all tightly coupled children are added with this call). AddPredefinedNode(SystemContext, instance); // register handler. method.OnCallMethod = new GenericMethodCalledEventHandler(DoMethodCall); #endregion #region Task #D6 - Add Support for Notifiers // enable subscriptions. root.EventNotifier = EventNotifiers.SubscribeToEvents; // creating notifier ensures events propogate up the hierarchy when the are produced. AddRootNotifier(root); // add link to server object. if (!externalReferences.TryGetValue(ObjectIds.Server, out references)) { externalReferences[ObjectIds.Server] = references = new List <IReference>(); } references.Add(new NodeStateReference(ReferenceTypeIds.HasNotifier, false, root.NodeId)); // add sub-notifiers. instance.EventNotifier = EventNotifiers.SubscribeToEvents; instance.AddNotifier(SystemContext, ReferenceTypeIds.HasNotifier, true, root); root.AddNotifier(SystemContext, ReferenceTypeIds.HasNotifier, false, instance); #endregion } }