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);
            }
        }
Exemplo n.º 2
0
        /// <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);
        }
Exemplo n.º 4
0
        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);
        }
Exemplo n.º 5
0
        /// <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);
        }
Exemplo n.º 6
0
        /// <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);
        }
Exemplo n.º 7
0
        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);
        }
Exemplo n.º 9
0
        /// <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);
        }
Exemplo n.º 10
0
        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());
            }
        }