/// <summary> /// Simulates a block by updating the state of the tags belonging to the condition. /// </summary> /// <param name="counter">The number of simulation cycles that have elapsed.</param> /// <param name="index">The index of the block within the system.</param> /// <param name="generator">An object which generates random data.</param> public void DoSimulation(long counter, int index, Opc.Ua.Test.DataGenerator generator) { try { TagsChangedEventHandler onTagsChanged = null; List <UnderlyingSystemTag> snapshots = new List <UnderlyingSystemTag>(); // update the tags. lock (m_tags) { onTagsChanged = OnTagsChanged; // do nothing if not monitored. if (onTagsChanged == null) { return; } for (int ii = 0; ii < m_tags.Count; ii++) { UnderlyingSystemTag tag = m_tags[ii]; UpdateTagValue(tag, generator); DataValue value = new DataValue(); value.Value = tag.Value; value.StatusCode = StatusCodes.Good; value.SourceTimestamp = tag.Timestamp; if (counter % (8 + (index % 4)) == 0) { UpdateTagMetadata(tag, generator); } snapshots.Add(tag.CreateSnapshot()); } } // report any tag changes after releasing the lock. if (onTagsChanged != null) { onTagsChanged(snapshots); } } catch (Exception e) { Utils.Trace(e, "Unexpected error running simulation for block {0}", m_name); } }
/// <summary> /// Updates the metadata for a tag. /// </summary> private bool UpdateTagMetadata( UnderlyingSystemTag tag, Opc.Ua.Test.DataGenerator generator) { switch (tag.TagType) { case UnderlyingSystemTagType.Analog: { if (tag.EuRange != null) { double[] range = new double[tag.EuRange.Length]; for (int ii = 0; ii < tag.EuRange.Length; ii++) { range[ii] = tag.EuRange[ii] + 1; } tag.EuRange = range; } break; } case UnderlyingSystemTagType.Digital: case UnderlyingSystemTagType.Enumerated: { if (tag.Labels != null) { string[] labels = new string[tag.Labels.Length]; for (int ii = 0; ii < tag.Labels.Length; ii++) { labels[ii] = generator.GetRandomString(); } tag.Labels = labels; } break; } default: { return(false); } } return(true); }
/// <summary> /// Returns a snapshot of the tags belonging to the block. /// </summary> /// <returns>The list of tags. Null if the block does not exist.</returns> public IList <UnderlyingSystemTag> GetTags() { lock (m_tags) { // create snapshots of the tags. UnderlyingSystemTag[] tags = new UnderlyingSystemTag[m_tags.Count]; for (int ii = 0; ii < m_tags.Count; ii++) { tags[ii] = m_tags[ii].CreateSnapshot(); } return(tags); } }
/// <summary> /// Finds the tag identified by the name. /// </summary> /// <param name="tagName">Name of the tag.</param> /// <returns>The tag if null; otherwise null.</returns> private UnderlyingSystemTag FindTag(string tagName) { lock (m_tags) { // look up tag. for (int ii = 0; ii < m_tags.Count; ii++) { UnderlyingSystemTag tag = m_tags[ii]; if (tag.Name == tagName) { return(tag); } } return(null); } }
/// <summary> /// Creates the tag. /// </summary> /// <param name="tagName">Name of the tag.</param> /// <param name="dataType">Type of the data.</param> /// <param name="tagType">Type of the tag.</param> /// <param name="engineeringUnits">The engineering units.</param> /// <param name="writeable">if set to <c>true</c> the tag is writeable.</param> public void CreateTag( string tagName, UnderlyingSystemDataType dataType, UnderlyingSystemTagType tagType, string engineeringUnits, bool writeable) { // create tag. UnderlyingSystemTag tag = new UnderlyingSystemTag(); tag.Block = this; tag.Name = tagName; tag.Description = null; tag.EngineeringUnits = engineeringUnits; tag.DataType = dataType; tag.TagType = tagType; tag.IsWriteable = writeable; tag.Labels = null; tag.EuRange = null; switch (tagType) { case UnderlyingSystemTagType.Analog: { tag.Description = "An analog value."; tag.TagType = UnderlyingSystemTagType.Analog; tag.EuRange = new double[] { 100, 0 }; break; } case UnderlyingSystemTagType.Digital: { tag.Description = "A digital value."; tag.TagType = UnderlyingSystemTagType.Digital; tag.Labels = new string[] { "Online", "Offline" }; break; } case UnderlyingSystemTagType.Enumerated: { tag.Description = "An enumerated value."; tag.TagType = UnderlyingSystemTagType.Enumerated; tag.Labels = new string[] { "Red", "Yellow", "Green" }; break; } default: { tag.Description = "A generic value."; break; } } // set an initial value. switch (tag.DataType) { case UnderlyingSystemDataType.Integer1: { tag.Value = (sbyte)0; break; } case UnderlyingSystemDataType.Integer2: { tag.Value = (short)0; break; } case UnderlyingSystemDataType.Integer4: { tag.Value = (int)0; break; } case UnderlyingSystemDataType.Real4: { tag.Value = (float)0; break; } case UnderlyingSystemDataType.String: { tag.Value = String.Empty; break; } } lock (m_tags) { m_tags.Add(tag); m_timestamp = DateTime.UtcNow; } }
/// <summary> /// Updates the metadata for a tag. /// </summary> private bool UpdateTagMetadata( UnderlyingSystemTag tag, Opc.Ua.Test.DataGenerator generator) { switch (tag.TagType) { case UnderlyingSystemTagType.Analog: { if (tag.EuRange != null) { double[] range = new double[tag.EuRange.Length]; for (int ii = 0; ii < tag.EuRange.Length; ii++) { range[ii] = tag.EuRange[ii]+1; } tag.EuRange = range; } break; } case UnderlyingSystemTagType.Digital: case UnderlyingSystemTagType.Enumerated: { if (tag.Labels != null) { string[] labels = new string[tag.Labels.Length]; for (int ii = 0; ii < tag.Labels.Length; ii++) { labels[ii] = generator.GetRandomString(); } tag.Labels = labels; } break; } default: { return false; } } return true; }
/// <summary> /// Updates the value of an tag. /// </summary> private bool UpdateTagValue( UnderlyingSystemTag tag, Opc.Ua.Test.DataGenerator generator) { // don't update writeable tags. if (tag.IsWriteable) { return false; } // check if a range applies to the value. int high = 0; int low = 0; switch (tag.TagType) { case UnderlyingSystemTagType.Analog: { if (tag.EuRange != null && tag.EuRange.Length >= 2) { high = (int)tag.EuRange[0]; low = (int)tag.EuRange[1]; } break; } case UnderlyingSystemTagType.Digital: { high = 1; low = 0; break; } case UnderlyingSystemTagType.Enumerated: { if (tag.Labels != null && tag.Labels.Length > 0) { high = tag.Labels.Length-1; low = 0; } break; } } // select a value in the range. int value = -1; if (high > low) { value = (generator.GetRandomUInt16()%(high - low + 1)) + low; } // cast value to correct type or generate a random value. switch (tag.DataType) { case UnderlyingSystemDataType.Integer1: { if (value == -1) { tag.Value = generator.GetRandomSByte(); } else { tag.Value = (sbyte)value; } break; } case UnderlyingSystemDataType.Integer2: { if (value == -1) { tag.Value = generator.GetRandomInt16(); } else { tag.Value = (short)value; } break; } case UnderlyingSystemDataType.Integer4: { if (value == -1) { tag.Value = generator.GetRandomInt32(); } else { tag.Value = (int)value; } break; } case UnderlyingSystemDataType.Real4: { if (value == -1) { tag.Value = generator.GetRandomFloat(); } else { tag.Value = (float)value; } break; } case UnderlyingSystemDataType.String: { tag.Value = generator.GetRandomString(); break; } } tag.Timestamp = DateTime.UtcNow; return true; }
/// <summary> /// Returns a snapshot of the tags belonging to the block. /// </summary> /// <returns>The list of tags. Null if the block does not exist.</returns> public IList<UnderlyingSystemTag> GetTags() { lock (m_tags) { // create snapshots of the tags. UnderlyingSystemTag[] tags = new UnderlyingSystemTag[m_tags.Count]; for (int ii = 0; ii < m_tags.Count; ii++) { tags[ii] = m_tags[ii].CreateSnapshot(); } return tags; } }
/// <summary> /// Updates a variable from a tag. /// </summary> /// <param name="context">The context.</param> /// <param name="tag">The tag.</param> /// <param name="variable">The variable to update.</param> private void UpdateVariable(ISystemContext context, UnderlyingSystemTag tag, BaseVariableState variable) { variable.Description = tag.Description; variable.Value = tag.Value; variable.Timestamp = tag.Timestamp; switch (tag.DataType) { case UnderlyingSystemDataType.Integer1: { variable.DataType = DataTypes.SByte; break; } case UnderlyingSystemDataType.Integer2: { variable.DataType = DataTypes.Int16; break; } case UnderlyingSystemDataType.Integer4: { variable.DataType = DataTypes.Int32; break; } case UnderlyingSystemDataType.Real4: { variable.DataType = DataTypes.Float; break; } case UnderlyingSystemDataType.String: { variable.DataType = DataTypes.String; break; } } variable.ValueRank = ValueRanks.Scalar; variable.ArrayDimensions = null; if (tag.IsWriteable) { variable.AccessLevel = AccessLevels.CurrentReadOrWrite; variable.UserAccessLevel = AccessLevels.CurrentReadOrWrite; } else { variable.AccessLevel = AccessLevels.CurrentRead; variable.UserAccessLevel = AccessLevels.CurrentRead; } variable.MinimumSamplingInterval = MinimumSamplingIntervals.Continuous; variable.Historizing = false; switch (tag.TagType) { case UnderlyingSystemTagType.Analog: { AnalogItemState node = variable as AnalogItemState; if (tag.EuRange != null) { if (tag.EuRange.Length >= 2 && node.EURange != null) { Range range = new Range(tag.EuRange[0], tag.EuRange[1]); node.EURange.Value = range; node.EURange.Timestamp = tag.Block.Timestamp; } if (tag.EuRange.Length >= 4 && node.InstrumentRange != null) { Range range = new Range(tag.EuRange[2], tag.EuRange[3]); node.InstrumentRange.Value = range; node.InstrumentRange.Timestamp = tag.Block.Timestamp; } } if (!String.IsNullOrEmpty(tag.EngineeringUnits) && node.EngineeringUnits != null) { EUInformation info = new EUInformation(); info.DisplayName = tag.EngineeringUnits; info.NamespaceUri = Namespaces.HistoricalAccess; node.EngineeringUnits.Value = info; node.EngineeringUnits.Timestamp = tag.Block.Timestamp; } break; } case UnderlyingSystemTagType.Digital: { TwoStateDiscreteState node = variable as TwoStateDiscreteState; if (tag.Labels != null && node.TrueState != null && node.FalseState != null) { if (tag.Labels.Length >= 2) { node.TrueState.Value = new LocalizedText(tag.Labels[0]); node.TrueState.Timestamp = tag.Block.Timestamp; node.FalseState.Value = new LocalizedText(tag.Labels[1]); node.FalseState.Timestamp = tag.Block.Timestamp; } } break; } case UnderlyingSystemTagType.Enumerated: { MultiStateDiscreteState node = variable as MultiStateDiscreteState; if (tag.Labels != null) { LocalizedText[] strings = new LocalizedText[tag.Labels.Length]; for (int ii = 0; ii < tag.Labels.Length; ii++) { strings[ii] = new LocalizedText(tag.Labels[ii]); } node.EnumStrings.Value = strings; node.EnumStrings.Timestamp = tag.Block.Timestamp; } break; } } }
/// <summary> /// Creates a variable from a tag. /// </summary> /// <param name="context">The context.</param> /// <param name="tag">The tag.</param> /// <returns>The variable that represents the tag.</returns> private BaseVariableState CreateVariable(ISystemContext context, UnderlyingSystemTag tag) { // create the variable type based on the tag type. BaseDataVariableState variable = null; switch (tag.TagType) { case UnderlyingSystemTagType.Analog: { AnalogItemState node = new AnalogItemState(this); if (tag.EngineeringUnits != null) { node.EngineeringUnits = new PropertyState <EUInformation>(node); } if (tag.EuRange.Length >= 4) { node.InstrumentRange = new PropertyState <Range>(node); } variable = node; break; } case UnderlyingSystemTagType.Digital: { TwoStateDiscreteState node = new TwoStateDiscreteState(this); variable = node; break; } case UnderlyingSystemTagType.Enumerated: { MultiStateDiscreteState node = new MultiStateDiscreteState(this); if (tag.Labels != null) { node.EnumStrings = new PropertyState <LocalizedText[]>(node); } variable = node; break; } default: { DataItemState node = new DataItemState(this); variable = node; break; } } // set the symbolic name and reference types. variable.SymbolicName = tag.Name; variable.ReferenceTypeId = ReferenceTypeIds.HasComponent; // initialize the variable from the type model. variable.Create( context, null, new QualifiedName(tag.Name, this.BrowseName.NamespaceIndex), null, true); // update the variable values. UpdateVariable(context, tag, variable); return(variable); }
/// <summary> /// Creates a variable from a tag. /// </summary> /// <param name="context">The context.</param> /// <param name="tag">The tag.</param> /// <returns>The variable that represents the tag.</returns> private BaseVariableState CreateVariable(ISystemContext context, UnderlyingSystemTag tag) { // create the variable type based on the tag type. BaseDataVariableState variable = null; switch (tag.TagType) { case UnderlyingSystemTagType.Analog: { AnalogItemState node = new AnalogItemState(this); if (tag.EngineeringUnits != null) { node.EngineeringUnits = new PropertyState<EUInformation>(node); } if (tag.EuRange.Length >= 4) { node.InstrumentRange = new PropertyState<Range>(node); } variable = node; break; } case UnderlyingSystemTagType.Digital: { TwoStateDiscreteState node = new TwoStateDiscreteState(this); variable = node; break; } case UnderlyingSystemTagType.Enumerated: { MultiStateDiscreteState node = new MultiStateDiscreteState(this); if (tag.Labels != null) { node.EnumStrings = new PropertyState<LocalizedText[]>(node); } variable = node; break; } default: { DataItemState node = new DataItemState(this); variable = node; break; } } // set the symbolic name and reference types. variable.SymbolicName = tag.Name; variable.ReferenceTypeId = ReferenceTypeIds.HasComponent; // initialize the variable from the type model. variable.Create( context, null, new QualifiedName(tag.Name, this.BrowseName.NamespaceIndex), null, true); // update the variable values. UpdateVariable(context, tag, variable); return variable; }
/// <summary> /// Updates the value of an tag. /// </summary> private bool UpdateTagValue( UnderlyingSystemTag tag, Opc.Ua.Test.DataGenerator generator) { // don't update writeable tags. if (tag.IsWriteable) { return(false); } // check if a range applies to the value. int high = 0; int low = 0; switch (tag.TagType) { case UnderlyingSystemTagType.Analog: { if (tag.EuRange != null && tag.EuRange.Length >= 2) { high = (int)tag.EuRange[0]; low = (int)tag.EuRange[1]; } break; } case UnderlyingSystemTagType.Digital: { high = 1; low = 0; break; } case UnderlyingSystemTagType.Enumerated: { if (tag.Labels != null && tag.Labels.Length > 0) { high = tag.Labels.Length - 1; low = 0; } break; } } // select a value in the range. int value = -1; if (high > low) { value = (generator.GetRandomUInt16() % (high - low + 1)) + low; } // cast value to correct type or generate a random value. switch (tag.DataType) { case UnderlyingSystemDataType.Integer1: { if (value == -1) { tag.Value = generator.GetRandomSByte(); } else { tag.Value = (sbyte)value; } break; } case UnderlyingSystemDataType.Integer2: { if (value == -1) { tag.Value = generator.GetRandomInt16(); } else { tag.Value = (short)value; } break; } case UnderlyingSystemDataType.Integer4: { if (value == -1) { tag.Value = generator.GetRandomInt32(); } else { tag.Value = (int)value; } break; } case UnderlyingSystemDataType.Real4: { if (value == -1) { tag.Value = generator.GetRandomFloat(); } else { tag.Value = (float)value; } break; } case UnderlyingSystemDataType.String: { tag.Value = generator.GetRandomString(); break; } } tag.Timestamp = DateTime.UtcNow; return(true); }
/// <summary> /// Writes the tag value. /// </summary> /// <param name="tagName">Name of the tag.</param> /// <param name="value">The value.</param> /// <returns>The status code for the operation.</returns> public uint WriteTagValue(string tagName, object value) { UnderlyingSystemTag tag = null; TagsChangedEventHandler onTagsChanged = null; lock (m_tags) { onTagsChanged = OnTagsChanged; // find the tag. tag = FindTag(tagName); if (tag == null) { return(StatusCodes.BadNodeIdUnknown); } // cast value to correct type. try { switch (tag.DataType) { case UnderlyingSystemDataType.Integer1: { tag.Value = (sbyte)value; break; } case UnderlyingSystemDataType.Integer2: { tag.Value = (short)value; break; } case UnderlyingSystemDataType.Integer4: { tag.Value = (int)value; break; } case UnderlyingSystemDataType.Real4: { tag.Value = (float)value; break; } case UnderlyingSystemDataType.String: { tag.Value = (string)value; break; } } } catch { return(StatusCodes.BadTypeMismatch); } // updated the timestamp. tag.Timestamp = DateTime.UtcNow; } // raise notification. if (tag != null && onTagsChanged != null) { onTagsChanged(new UnderlyingSystemTag[] { tag }); } return(StatusCodes.Good); }