private void IncreaseNodes(BaseDataVariableState[] nodes, NodeType type, StatusCode status, bool addBadValue) { if (nodes == null || nodes.Length == 0) { Logger.Warning("Invalid argument {argument} provided.", nodes); return; } for (int nodeIndex = 0; nodeIndex < nodes.Length; nodeIndex++) { object value = null; if (StatusCode.IsNotBad(status) || addBadValue) { switch (type) { case NodeType.Double: value = nodes[nodeIndex].Value != null ? (double)nodes[nodeIndex].Value + 0.1 : 0.0; break; case NodeType.Bool: value = nodes[nodeIndex].Value != null ? !(bool)nodes[nodeIndex].Value : true; break; case NodeType.UIntArray: uint[] arrayValue = (uint[])nodes[nodeIndex].Value; if (arrayValue != null) { for (int arrayIndex = 0; arrayIndex < arrayValue?.Length; arrayIndex++) { arrayValue[arrayIndex]++; } } else { arrayValue = new uint[32]; } value = arrayValue; break; case NodeType.UInt: default: value = nodes[nodeIndex].Value != null ? (uint)nodes[nodeIndex].Value + 1 : 0; break; } } nodes[nodeIndex].StatusCode = status; nodes[nodeIndex].Value = value; nodes[nodeIndex].Timestamp = DateTime.Now; nodes[nodeIndex].ClearChangeMasks(SystemContext, false); } }
/// <summary> /// Processes an incoming value. /// </summary> /// <remarks> /// Returns a set of processed data value if an interval is complete. /// </remarks> public IList <DataValue> ProcessValue(DataValue value, ServiceResult result) { // returns the processed values. IList <DataValue> processedValues = GetProcessedValues(); // check for bad status. if (StatusCode.IsNotBad(m_worstStatus)) { if (StatusCode.IsBad(value.StatusCode)) { m_worstStatus = value.StatusCode; } } // check for uncertain status. if (StatusCode.IsGood(m_worstStatus)) { if (StatusCode.IsUncertain(value.StatusCode)) { m_worstStatus = value.StatusCode; } } // process good or uncertain value. if (StatusCode.IsNotBad(value.StatusCode)) { // save the last data type used. TypeInfo typeInfo = TypeInfo.Construct(value.Value); if (m_typeInfo == null || m_typeInfo.BuiltInType != typeInfo.BuiltInType) { m_typeInfo = typeInfo; } // process the sample. try { double sample = Convert.ToDouble(value.Value, CultureInfo.InvariantCulture); ProcessValue(sample, value.StatusCode, value.SourceTimestamp, m_startTime, m_processingInterval); } catch (Exception) { m_worstStatus = StatusCodes.BadTypeMismatch; } } return(processedValues); }
/// <summary> /// Calculate the Start2 and End2 aggregates for the timeslice. /// </summary> protected DataValue ComputeStartEnd2(TimeSlice slice, bool returnEnd) { // get the values in the slice. List <DataValue> values = GetValuesWithSimpleBounds(slice); // check for empty slice. if (values == null || values.Count == 0) { return(GetNoDataValue(slice)); } DataValue value = null; // return start bound. if ((!returnEnd && !TimeFlowsBackward) || (returnEnd && TimeFlowsBackward)) { value = values[0]; } // return end bound. else { value = values[values.Count - 1]; } if (!IsGood(value)) { value.StatusCode = StatusCodes.BadNoData; } if (returnEnd) { value.SourceTimestamp = GetTimestamp(slice); value.ServerTimestamp = GetTimestamp(slice); if (StatusCode.IsNotBad(value.StatusCode)) { value.StatusCode = value.StatusCode.SetAggregateBits(AggregateBits.Calculated); } } return(value); }
public override DataValue Compute(IAggregationContext context, TimeSlice bucket, AggregateState state) { int numGood = 0; int numBad = 0; double total = 0.0; foreach (DataValue v in bucket.Values) { if (state.RawValueIsGood(v)) { numGood += 1; total += Convert.ToDouble(v.Value, CultureInfo.InvariantCulture); } else { numBad += 1; } } DataValue retval = new DataValue { SourceTimestamp = bucket.From }; StatusCode code = ComputeStatus(context, numGood, numBad, bucket).Code; code.AggregateBits = AggregateBits.Calculated; if (bucket.Incomplete) { code.AggregateBits |= AggregateBits.Partial; } if (StatusCode.IsNotBad(code)) { retval.Value = total; } retval.StatusCode = code; GoodDataCount = numGood; return(retval); }
/// <summary> /// Reads the attributes, verifies the results and updates the nodes. /// </summary> private bool Write(WriteValueCollection nodesToWrite) { bool success = true; StatusCodeCollection results = null; DiagnosticInfoCollection diagnosticInfos = null; RequestHeader requestHeader = new RequestHeader(); requestHeader.ReturnDiagnostics = 0; try { Session.Write( requestHeader, nodesToWrite, out results, out diagnosticInfos); } catch (System.ServiceModel.CommunicationException e) { Log("WARNING: Communication error (random data may have resulted in a message that is too large). {0}", e.Message); return(true); } catch (System.Xml.XmlException e) { Log("WARNING: XML parsing error (random data may have resulted in a message that is too large). {0}", e.Message); return(true); } catch (ServiceResultException e) { if (e.StatusCode == StatusCodes.BadEncodingLimitsExceeded) { Log("WARNING: Communication error (random data may have resulted in a message that is too large). {0}", e.Message); return(true); } throw new ServiceResultException(new ServiceResult(e)); } ClientBase.ValidateResponse(results, nodesToWrite); ClientBase.ValidateDiagnosticInfos(diagnosticInfos, nodesToWrite); // check diagnostics. if (diagnosticInfos != null && diagnosticInfos.Count > 0) { Log("Returned non-empty DiagnosticInfos array during Write."); return(false); } // check results. ReadValueIdCollection nodesToRead = new ReadValueIdCollection(); for (int ii = 0; ii < nodesToWrite.Count; ii++) { WriteValue request = nodesToWrite[ii]; TestVariable variable = (TestVariable)request.Handle; if (results[ii] == StatusCodes.BadUserAccessDenied) { continue; } if (results[ii] == StatusCodes.BadNotWritable) { Log( "Write failed when writing a writeable value '{0}'. NodeId = {1}, Value = {2}, StatusCode = {3}", variable.Variable, variable.Variable.NodeId, request.Value.WrappedValue, results[ii]); success = false; break; } if (StatusCode.IsBad(results[ii])) { if (request.Value.StatusCode != StatusCodes.Good) { if (results[ii] != StatusCodes.BadWriteNotSupported) { Log( "Unexpected error when writing the StatusCode for a Value '{0}'. NodeId = {1}, Value = {2}, StatusCode = {3}", variable.Variable, variable.Variable.NodeId, request.Value.WrappedValue, results[ii]); success = false; break; } continue; } if (request.Value.SourceTimestamp != DateTime.MinValue || request.Value.ServerTimestamp != DateTime.MinValue) { if (results[ii] != StatusCodes.BadWriteNotSupported) { Log( "Unexpected error when writing the Timestamp for a Value '{0}'. NodeId = {1}, Value = {2}, StatusCode = {3}", variable.Variable, variable.Variable.NodeId, request.Value.WrappedValue, results[ii]); success = false; break; } continue; } if (results[ii] != StatusCodes.BadTypeMismatch && results[ii] != StatusCodes.BadOutOfRange) { Log( "Unexpected error when writing a valid value '{0}'. NodeId = {1}, Value = {2}, StatusCode = {3}", variable.Variable, variable.Variable.NodeId, request.Value.WrappedValue, results[ii]); success = false; break; } continue; } ReadValueId nodeToRead = new ReadValueId(); nodeToRead.NodeId = request.NodeId; nodeToRead.AttributeId = request.AttributeId; nodeToRead.IndexRange = request.IndexRange; nodeToRead.Handle = request.Handle; nodesToRead.Add(nodeToRead); } // skip read back on failed. if (!success) { return(success); } // check if nothing more do to. if (nodesToRead.Count == 0) { return(true); } requestHeader = new RequestHeader(); requestHeader.ReturnDiagnostics = 0; DataValueCollection values = new DataValueCollection(); try { Session.Read( requestHeader, 0, TimestampsToReturn.Both, nodesToRead, out values, out diagnosticInfos); } catch (System.ServiceModel.CommunicationException e) { Log("WARNING: Communication error (random data may have resulted in a message that is too large). {0}", e.Message); return(true); } catch (System.Xml.XmlException e) { Log("WARNING: XML parsing error (random data may have resulted in a message that is too large). {0}", e.Message); return(true); } catch (ServiceResultException e) { if (e.StatusCode == StatusCodes.BadEncodingLimitsExceeded) { Log("WARNING: Communication error (random data may have resulted in a message that is too large). {0}", e.Message); return(true); } throw new ServiceResultException(new ServiceResult(e)); } ClientBase.ValidateResponse(values, nodesToRead); ClientBase.ValidateDiagnosticInfos(diagnosticInfos, nodesToRead); // check diagnostics. if (diagnosticInfos != null && diagnosticInfos.Count > 0) { Log("Returned non-empty DiagnosticInfos array during Read."); return(false); } for (int ii = 0; ii < nodesToRead.Count; ii++) { ReadValueId request = nodesToRead[ii]; TestVariable variable = (TestVariable)request.Handle; DataValue valueWritten = variable.Values[variable.Values.Count - 1]; if (StatusCode.IsBad(values[ii].StatusCode) && StatusCode.IsNotBad(valueWritten.StatusCode)) { Log( "Could not read back the value written '{0}'. NodeId = {1}, Value = {2}, StatusCode = {3}", variable.Variable, variable.Variable.NodeId, valueWritten.WrappedValue, values[ii].StatusCode); success = false; break; } Opc.Ua.Test.DataComparer comparer = new Opc.Ua.Test.DataComparer(Session.MessageContext); comparer.ThrowOnError = false; if (!comparer.CompareVariant(values[ii].WrappedValue, valueWritten.WrappedValue)) { Log( "Read back value does not match the value written '{0}'. NodeId = {1}, Value = {2}, ReadValue = {3}", variable.Variable, variable.Variable.NodeId, valueWritten.WrappedValue, values[ii].WrappedValue); success = false; break; } if (valueWritten.StatusCode != StatusCodes.Good) { if (values[ii].StatusCode != valueWritten.StatusCode) { Log( "Read back StatusCode does not match the StatusCode written '{0}'. NodeId = {1}, StatusCode = {2}, ReadStatusCode = {3}", variable.Variable, variable.Variable.NodeId, valueWritten.StatusCode, values[ii].StatusCode); success = false; break; } } if (valueWritten.SourceTimestamp != DateTime.MinValue) { if (values[ii].SourceTimestamp != valueWritten.SourceTimestamp) { Log( "Read back ServerTimestamp does not match the ServerTimestamp written '{0}'. NodeId = {1}, Timestamp = {2}, ReadTimestamp = {3}", variable.Variable, variable.Variable.NodeId, valueWritten.SourceTimestamp, values[ii].SourceTimestamp); success = false; break; } } } return(success); }
/// <summary> /// Calculates the StdDev, Variance, StdDev2 and Variance2 aggregates for the timeslice. /// </summary> protected DataValue ComputeTimeAverage(TimeSlice slice, bool useSimpleBounds, int valueType) { // get the values in the slice. List <DataValue> values = null; if (useSimpleBounds) { values = GetValuesWithSimpleBounds(slice); } else { values = GetValuesWithInterpolatedBounds(slice); } // check for empty slice. if (values == null || values.Count == 0) { return(GetNoDataValue(slice)); } // get the regions. List <SubRegion> regions = GetRegionsInValueSet(values, !useSimpleBounds, Stepped); double total = 0; double totalDuration = 0; bool nonGoodRegionsExists = false; for (int ii = 0; ii < regions.Count; ii++) { double duration = regions[ii].Duration / 1000.0; if (StatusCode.IsNotBad(regions[ii].StatusCode)) { total += (regions[ii].StartValue + regions[ii].EndValue) * duration / 2; totalDuration += duration; } if (StatusCode.IsNotGood(regions[ii].StatusCode)) { nonGoodRegionsExists = true; } } // check if no good data. if (totalDuration == 0) { return(GetNoDataValue(slice)); } // select the result. double result = 0; switch (valueType) { case 1: { result = total / totalDuration; break; } case 2: { result = total; break; } } // set the timestamp and status. DataValue value = new DataValue(); value.WrappedValue = new Variant(result, TypeInfo.Scalars.Double); value.SourceTimestamp = GetTimestamp(slice); value.ServerTimestamp = GetTimestamp(slice); if (useSimpleBounds) { value.StatusCode = GetTimeBasedStatusCode(regions, value.StatusCode); } else { value.StatusCode = StatusCodes.Good; if (nonGoodRegionsExists) { value.StatusCode = StatusCodes.UncertainDataSubNormal; } } value.StatusCode = value.StatusCode.SetAggregateBits(AggregateBits.Calculated); // return result. return(value); }
public override DataValue Compute(IAggregationContext context, TimeSlice bucket, AggregateState state) { DataValue retval = new DataValue { SourceTimestamp = bucket.From }; DataValue initValue = bucket.EarlyBound.Value, finalValue = bucket.LateBound.Value; IEnumerator<DataValue> enumerator = bucket.Values.GetEnumerator(); StatusCode code = StatusCodes.BadNoData; if (initValue == null && enumerator.MoveNext()) // first element { initValue = enumerator.Current; } if (finalValue == null) { while (enumerator.MoveNext()) { finalValue = enumerator.Current; } } if (initValue != null && finalValue != null) { int numGood = 0; int numBad = 0; double total = 0.0; double early = 0.0; double late = 0.0; double width = 0.0; Debug.WriteLine(String.Format("bucket starts @ {0}, ends @ {1}", bucket.From.TimeOfDay, bucket.To.TimeOfDay)); if ((initValue.StatusCode.AggregateBits & AggregateBits.Raw) == 0) { if (state.RawValueIsGood(initValue)) numGood += 1; else numBad += 1; } if ((finalValue.StatusCode.AggregateBits & AggregateBits.Raw) == 0) { if (state.RawValueIsGood(finalValue)) numGood += 1; else numBad += 1; } DataValue preceding = initValue; foreach (DataValue v in bucket.Values) { if (state.RawValueIsGood(v)) { numGood += 1; early = Convert.ToDouble(preceding.Value, CultureInfo.InvariantCulture); late = Convert.ToDouble(v.Value, CultureInfo.InvariantCulture); width = (v.SourceTimestamp - preceding.SourceTimestamp).TotalMilliseconds; total += SteppedVariable ? width * early : width * (late + early) / 2; preceding = v; } else { numBad += 1; } } early = Convert.ToDouble(preceding.Value, CultureInfo.InvariantCulture); late = Convert.ToDouble(finalValue.Value, CultureInfo.InvariantCulture); width = (finalValue.SourceTimestamp - preceding.SourceTimestamp).TotalMilliseconds; total += SteppedVariable ? width * early : width * (late + early) / 2; retval.Value = total; code = ComputeStatus(context, numGood, numBad, bucket).Code; } code.AggregateBits = AggregateBits.Calculated; if (StatusCode.IsNotBad(code) && bucket.Incomplete) code.AggregateBits |= AggregateBits.Partial; retval.StatusCode = code; return retval; }
/// <summary> /// Updates the history. /// </summary> public uint UpdateHistory(SystemContext context, DataValue value, PerformUpdateType performUpdateType) { var replaced = false; if (performUpdateType == PerformUpdateType.Remove) { return(StatusCodes.BadNotSupported); } if (StatusCode.IsNotBad(value.StatusCode)) { var typeInfo = value.WrappedValue.TypeInfo; if (typeInfo == null) { typeInfo = TypeInfo.Construct(value.Value); } if (typeInfo == null || typeInfo.BuiltInType != ArchiveItem.DataType || typeInfo.ValueRank != ValueRanks.Scalar) { return(StatusCodes.BadTypeMismatch); } } var filter = string.Format(System.Globalization.CultureInfo.InvariantCulture, "SourceTimestamp = #{0}#", value.SourceTimestamp); var view = new DataView( ArchiveItem.DataSet.Tables[0], filter, null, DataViewRowState.CurrentRows); DataRow row = null; var ii = 0; for (; ii < view.Count;) { if (performUpdateType == PerformUpdateType.Insert) { return(StatusCodes.BadEntryExists); } // add record indicating it was replaced. var modifiedRow = ArchiveItem.DataSet.Tables[1].NewRow(); modifiedRow[0] = view[ii].Row[0]; modifiedRow[1] = view[ii].Row[1]; modifiedRow[2] = view[ii].Row[2]; modifiedRow[3] = view[ii].Row[3]; modifiedRow[4] = view[ii].Row[4]; modifiedRow[5] = HistoryUpdateType.Replace; modifiedRow[6] = GetModificationInfo(context, HistoryUpdateType.Replace); ArchiveItem.DataSet.Tables[1].Rows.Add(modifiedRow); replaced = true; row = view[ii].Row; break; } // add record indicating it was inserted. if (!replaced) { if (performUpdateType == PerformUpdateType.Replace) { return(StatusCodes.BadNoEntryExists); } var modifiedRow = ArchiveItem.DataSet.Tables[1].NewRow(); modifiedRow[0] = value.SourceTimestamp; modifiedRow[1] = value.ServerTimestamp; modifiedRow[2] = value; if (value.WrappedValue.TypeInfo != null) { modifiedRow[3] = value.WrappedValue.TypeInfo.BuiltInType; modifiedRow[4] = value.WrappedValue.TypeInfo.ValueRank; } else { modifiedRow[3] = BuiltInType.Variant; modifiedRow[4] = ValueRanks.Scalar; } modifiedRow[5] = HistoryUpdateType.Insert; modifiedRow[6] = GetModificationInfo(context, HistoryUpdateType.Insert); ArchiveItem.DataSet.Tables[1].Rows.Add(modifiedRow); row = ArchiveItem.DataSet.Tables[0].NewRow(); } // add/update new record. row[0] = value.SourceTimestamp; row[1] = value.ServerTimestamp; row[2] = value; if (value.WrappedValue.TypeInfo != null) { row[3] = value.WrappedValue.TypeInfo.BuiltInType; row[4] = value.WrappedValue.TypeInfo.ValueRank; } else { row[3] = BuiltInType.Variant; row[4] = ValueRanks.Scalar; } if (!replaced) { ArchiveItem.DataSet.Tables[0].Rows.Add(row); } // accept all changes. ArchiveItem.DataSet.AcceptChanges(); return(StatusCodes.Good); }
/// <summary> /// Calculates the DurationGood and DurationBad aggregates for the timeslice. /// </summary> protected DataValue ComputeWorstQuality(TimeSlice slice, bool includeBounds) { // get the values in the slice. List <DataValue> values = null; if (!includeBounds) { values = GetValues(slice); } else { values = GetValuesWithSimpleBounds(slice); } // check for empty slice. if (values == null || values.Count == 0) { return(GetNoDataValue(slice)); } // get the regions. List <SubRegion> regions = GetRegionsInValueSet(values, false, true); StatusCode worstQuality = StatusCodes.Good; int badQualityCount = 0; int uncertainQualityCount = 0; for (int ii = 0; ii < values.Count; ii++) { StatusCode quality = values[ii].StatusCode; if (StatusCode.IsBad(quality)) { badQualityCount++; if (StatusCode.IsNotBad(worstQuality)) { worstQuality = quality.CodeBits; } continue; } if (StatusCode.IsUncertain(quality)) { uncertainQualityCount++; if (StatusCode.IsGood(worstQuality)) { worstQuality = quality.CodeBits; } continue; } } // set the timestamp and status. DataValue value = new DataValue(); value.WrappedValue = new Variant(worstQuality, TypeInfo.Scalars.StatusCode); value.SourceTimestamp = GetTimestamp(slice); value.ServerTimestamp = GetTimestamp(slice); value.StatusCode = value.StatusCode.SetAggregateBits(AggregateBits.Calculated); if ((StatusCode.IsBad(worstQuality) && badQualityCount > 1) || (StatusCode.IsUncertain(worstQuality) && uncertainQualityCount > 1)) { value.StatusCode = value.StatusCode.SetAggregateBits(value.StatusCode.AggregateBits | AggregateBits.MultipleValues); } // return result. return(value); }
static void DoTest(TestCase test, string filePath) { List <DataValue> expectedValues = GetExpectedResults(test.ExpectedResultsPath, test.TestId); ArchiveItem item = new ArchiveItem(test.DataPath, Assembly.GetExecutingAssembly(), test.DataPath); DataFileReader reader = new DataFileReader(); reader.LoadConfiguration(null, item); reader.LoadHistoryData(null, item); AggregateConfiguration configuration = new AggregateConfiguration(); configuration.PercentDataBad = 100; configuration.PercentDataGood = 100; configuration.TreatUncertainAsBad = test.TreatUncertainAsBad; configuration.UseSlopedExtrapolation = test.UseSlopedExtrapolation; configuration.UseServerCapabilitiesDefaults = false; DateTime startTime = DateTime.UtcNow; startTime = new DateTime(startTime.Year, startTime.Month, startTime.Day, startTime.Hour, 0, 0, DateTimeKind.Utc); AggregateCalculator calculator = new AggregateCalculator( test.AggregateId, startTime.AddSeconds(0), startTime.AddSeconds(100), 5000, test.Stepped, configuration); StringBuilder buffer = new StringBuilder(); List <DataValue> values = new List <DataValue>(); foreach (DataRowView row in item.DataSet.Tables[0].DefaultView) { DataValue rawValue = (DataValue)row.Row[2]; if (!calculator.QueueRawValue(rawValue)) { Utils.Trace("Oops!"); continue; } DataValue processedValue = calculator.GetProcessedValue(false); if (processedValue != null) { values.Add(processedValue); } } for (DataValue processedValue = calculator.GetProcessedValue(true); processedValue != null; processedValue = calculator.GetProcessedValue(true)) { values.Add(processedValue); } for (int ii = 0; ii < values.Count && ii < expectedValues.Count; ii++) { if (values[ii].SourceTimestamp != expectedValues[ii].SourceTimestamp) { Utils.Trace("Wrong Status Timestamp"); continue; } if (values[ii].StatusCode != expectedValues[ii].StatusCode) { Utils.Trace("Wrong Status Code"); continue; } if (StatusCode.IsNotBad(values[ii].StatusCode)) { double value1 = Math.Round(Convert.ToDouble(values[ii].Value), 4); double value2 = Math.Round(Convert.ToDouble(expectedValues[ii].Value), 4); if (value1 != value2) { Utils.Trace("Wrong Value"); continue; } } } foreach (DataValue processedValue in values) { buffer.Append(processedValue.SourceTimestamp.ToString("HH:mm:ss")); buffer.Append(", "); buffer.Append(processedValue.WrappedValue); buffer.Append(", "); buffer.Append(new StatusCode(processedValue.StatusCode.CodeBits)); buffer.Append(", "); buffer.Append(processedValue.StatusCode.AggregateBits); buffer.Append("\r\n"); } // write to the file. using (StreamWriter writer = new StreamWriter(filePath)) { writer.Write(buffer.ToString()); } }