/// <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)
            {
                // create a object to represent the process being controlled.
                BaseObjectState process = new BaseObjectState(null);

                process.NodeId = new NodeId(1, NamespaceIndex);
                process.BrowseName = new QualifiedName("My Process", NamespaceIndex);
                process.DisplayName = process.BrowseName.Name;
                process.TypeDefinitionId = ObjectTypeIds.BaseObjectType; 

                // ensure the process object 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>();
                }

                process.AddReference(ReferenceTypeIds.Organizes, true, ObjectIds.ObjectsFolder);
                references.Add(new NodeStateReference(ReferenceTypeIds.Organizes, false, process.NodeId));

                // a property to report the process state.
                PropertyState<uint> state = m_stateNode = new PropertyState<uint>(process);

                state.NodeId = new NodeId(2, NamespaceIndex);
                state.BrowseName = new QualifiedName("State", NamespaceIndex);
                state.DisplayName = state.BrowseName.Name;
                state.TypeDefinitionId = VariableTypeIds.PropertyType;
                state.ReferenceTypeId = ReferenceTypeIds.HasProperty;
                state.DataType = DataTypeIds.UInt32;
                state.ValueRank = ValueRanks.Scalar;

                process.AddChild(state);

                // a method to start the process.
                MethodState start = new MethodState(process);

                start.NodeId = new NodeId(3, NamespaceIndex);
                start.BrowseName = new QualifiedName("Start", NamespaceIndex);
                start.DisplayName = start.BrowseName.Name;
                start.ReferenceTypeId = ReferenceTypeIds.HasComponent;
                start.UserExecutable = true;
                start.Executable = true;

                // add input arguments.
                start.InputArguments = new PropertyState<Argument[]>(start);
                start.InputArguments.NodeId = new NodeId(4, NamespaceIndex);
                start.InputArguments.BrowseName = BrowseNames.InputArguments;
                start.InputArguments.DisplayName = start.InputArguments.BrowseName.Name;
                start.InputArguments.TypeDefinitionId = VariableTypeIds.PropertyType;
                start.InputArguments.ReferenceTypeId = ReferenceTypeIds.HasProperty;
                start.InputArguments.DataType = DataTypeIds.Argument;
                start.InputArguments.ValueRank = ValueRanks.OneDimension;

                Argument[] args = new Argument[2];
                args[0] = new Argument();
                args[0].Name = "Initial State";
                args[0].Description = "The initialize state for the process.";
                args[0].DataType = DataTypeIds.UInt32;
                args[0].ValueRank = ValueRanks.Scalar;

                args[1] = new Argument();
                args[1].Name = "Final State";
                args[1].Description = "The final state for the process.";
                args[1].DataType = DataTypeIds.UInt32;
                args[1].ValueRank = ValueRanks.Scalar;

                start.InputArguments.Value = args;

                // add output arguments.
                start.OutputArguments = new PropertyState<Argument[]>(start);
                start.OutputArguments.NodeId = new NodeId(5, NamespaceIndex);
                start.OutputArguments.BrowseName = BrowseNames.OutputArguments;
                start.OutputArguments.DisplayName = start.OutputArguments.BrowseName.Name;
                start.OutputArguments.TypeDefinitionId = VariableTypeIds.PropertyType;
                start.OutputArguments.ReferenceTypeId = ReferenceTypeIds.HasProperty;
                start.OutputArguments.DataType = DataTypeIds.Argument;
                start.OutputArguments.ValueRank = ValueRanks.OneDimension;

                args = new Argument[2];
                args[0] = new Argument();
                args[0].Name = "Revised Initial State";
                args[0].Description = "The revised initialize state for the process.";
                args[0].DataType = DataTypeIds.UInt32;
                args[0].ValueRank = ValueRanks.Scalar;

                args[1] = new Argument();
                args[1].Name = "Revised Final State";
                args[1].Description = "The revised final state for the process.";
                args[1].DataType = DataTypeIds.UInt32;
                args[1].ValueRank = ValueRanks.Scalar;

                start.OutputArguments.Value = args;

                process.AddChild(start);

                // save in dictionary. 
                AddPredefinedNode(SystemContext, process);

                // set up method handlers. 
                start.OnCallMethod = new GenericMethodCalledEventHandler(OnStart);
            } 
        }
Exemple #2
0
        /// <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)
            {
                BaseObjectState trigger = new BaseObjectState(null);

                trigger.NodeId = new NodeId(1, NamespaceIndex);
                trigger.BrowseName = new QualifiedName("Trigger", NamespaceIndex);
                trigger.DisplayName = trigger.BrowseName.Name;
                trigger.TypeDefinitionId = ObjectTypeIds.BaseObjectType; 

                // ensure trigger 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>();
                }

                trigger.AddReference(ReferenceTypeIds.Organizes, true, ObjectIds.ObjectsFolder);
                references.Add(new NodeStateReference(ReferenceTypeIds.Organizes, false, trigger.NodeId));

                PropertyState property = new PropertyState(trigger);

                property.NodeId = new NodeId(2, NamespaceIndex);
                property.BrowseName = new QualifiedName("Matrix", NamespaceIndex);
                property.DisplayName = property.BrowseName.Name;
                property.TypeDefinitionId = VariableTypeIds.PropertyType;
                property.ReferenceTypeId = ReferenceTypeIds.HasProperty;
                property.DataType = DataTypeIds.Int32;
                property.ValueRank = ValueRanks.TwoDimensions;
                property.ArrayDimensions = new ReadOnlyList<uint>(new uint[] { 2, 2 });

                trigger.AddChild(property);

                // save in dictionary. 
                AddPredefinedNode(SystemContext, trigger);

                ReferenceTypeState referenceType = new ReferenceTypeState();

                referenceType.NodeId = new NodeId(3, NamespaceIndex);
                referenceType.BrowseName = new QualifiedName("IsTriggerSource", NamespaceIndex);
                referenceType.DisplayName = referenceType.BrowseName.Name;
                referenceType.InverseName = new LocalizedText("IsSourceOfTrigger");
                referenceType.SuperTypeId = ReferenceTypeIds.NonHierarchicalReferences;

                if (!externalReferences.TryGetValue(ObjectIds.Server, out references))
                {
                    externalReferences[ObjectIds.Server] = references = new List<IReference>();
                }

                trigger.AddReference(referenceType.NodeId, false, ObjectIds.Server);
                references.Add(new NodeStateReference(referenceType.NodeId, true, trigger.NodeId));

                // save in dictionary. 
                AddPredefinedNode(SystemContext, referenceType);
            } 
        }
        /// <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)
            {
                // create a object to represent the process being controlled.
                BaseObjectState process = new BaseObjectState(null);

                process.NodeId = new NodeId(1, NamespaceIndex);
                process.BrowseName = new QualifiedName("My Process", NamespaceIndex);
                process.DisplayName = process.BrowseName.Name;
                process.TypeDefinitionId = ObjectTypeIds.BaseObjectType; 

                // ensure the process object 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>();
                }

                process.AddReference(ReferenceTypeIds.Organizes, true, ObjectIds.ObjectsFolder);
                references.Add(new NodeStateReference(ReferenceTypeIds.Organizes, false, process.NodeId));

                // a property to report the process state.
                PropertyState<string> state = new PropertyState<string>(process);

                state.NodeId = new NodeId(2, NamespaceIndex);
                state.BrowseName = new QualifiedName("LogFilePath", NamespaceIndex);
                state.DisplayName = state.BrowseName.Name;
                state.TypeDefinitionId = VariableTypeIds.PropertyType;
                state.ReferenceTypeId = ReferenceTypeIds.HasProperty;
                state.DataType = DataTypeIds.String;
                state.ValueRank = ValueRanks.Scalar;
                state.AccessLevel = AccessLevels.CurrentReadOrWrite;
                state.UserAccessLevel = AccessLevels.CurrentRead;
                state.Value = ".\\Log.txt";

                process.AddChild(state);
                
                state.OnReadUserAccessLevel = OnReadUserAccessLevel;
                state.OnSimpleWriteValue = OnWriteValue;

                // save in dictionary. 
                AddPredefinedNode(SystemContext, process);
            } 
        }
        /// <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
            }
        }