iPerl head failure rate is monitored by Various.StatisticsMonitoring component, ver. 2.26.1458

This commit is contained in:
Milan Hanajik 2020-05-05 15:42:15 +02:00
parent 05f72bc9f7
commit bc2804d0b9
14 changed files with 414 additions and 316 deletions

View File

@ -1,5 +1,5 @@
///
/// Copyright (c) 2013-2018 Sensus Slovensko a.s.
/// Copyright (c) 2013-2020 Sensus Slovensko a.s.
///
namespace TBF.BenchControl
{
@ -155,6 +155,8 @@ namespace TBF.BenchControl
ResultsProcessed, /// Event triggers
ErrorProcessingResults,
StatisticsProcessed, /// Statistics monitoring (Event triggers)
/// Timer events
TimerExpired,

View File

@ -0,0 +1,21 @@
///
/// Copyright (c) 2020 Sensus Slovensko a.s.
///
using System;
using System.Collections.Generic;
using TBF.BenchControl.Generic;
using Results.Entities;
namespace TBF.BenchControl.GenericDevices
{
public interface IStatisticsMonitoring : IComponent
{
/// <summary>
/// Process recent results and monitor obtained statistics
/// (failure rates of hardware components, etc.)
/// </summary>
/// <param name="lastBatchNr">Number of the last saved batch</param>
/// <returns>Reference to the operation</returns>
IOperation ProcessStatisticsOp(int lastBatchNr);
}
}

View File

@ -1,27 +0,0 @@
///
/// Copyright (c) 2020 Sensus Slovensko a.s.
///
using System;
using System.Collections.Generic;
using TBF.BenchControl.Generic;
namespace TBF.BenchControl.Output.EventTriggers.Statistics
{
public class Factory : IComponentFactory
{
public string ClassName { get { return this.GetType().Namespace.Substring(17); } }
public void ResetStaticProperties() { Trigger.ResetStaticProperties(); }
public IComponent DummyComponent() { return new Trigger(); }
public IComponent GetComponent(IComponentCfg cfg, IList<IComponent> components) { return new Trigger(cfg); }
public IComponentCfg DefaultConfig() { return new TriggerCfg(this.GetType().Namespace.Substring(24), this); }
public IComponentCfg CmpntCfgFromCmpntEntity(Config.Entities.Component component)
{
return ComponentCfgBase.CreateFromDbEntity(TriggerCfg.Serializer, component, this);;
}
}
}

View File

@ -1,106 +0,0 @@
///
/// Copyright (c) 2020 Sensus Slovensko a.s.
///
using System;
using log4net;
namespace TBF.BenchControl.Output.EventTriggers.Statistics
{
public class Trigger : ComponentBase, IOperation, GenericDevices.IEventTrigger
{
private static readonly ILog log = LogManager.GetLogger(typeof(Trigger));
public override string ToString() { return string.Format("{0}({1})", ClassName, Cfg.ToString(1)); }
readonly TriggerCfg triggerCfg;
Results.Entities.Batch batch;
public Trigger() {}
public Trigger(Generic.IComponentCfg cfg)
: base(cfg)
{
triggerCfg = cfg as TriggerCfg;
ApplyConfig();
log.Debug(this.ToString());
}
void ApplyConfig()
{
}
#region Configuration Change Handling
public static void OnCfgChange(object sender, CfgChangeArgs args)
{
if (CfgChangeHandler == null) return;
try { CfgChangeHandler(sender, args); }
catch (Exception e) { log.Error("CfgChangeHandler(...) failed", e); }
}
public static event EventHandler<CfgChangeArgs> CfgChangeHandler;
public override void StartChangeHandler()
{
CfgChangeHandler += delegate(object sender, CfgChangeArgs args)
{
TriggerCfg newCfg = args.Cfg as TriggerCfg;
if (newCfg != null && newCfg.Name.Equals(Name))
{
if (args.Command == CfgChangeCmd.CfgChange)
{
triggerCfg.EventSource = newCfg.EventSource;
triggerCfg.Culture = newCfg.Culture;
triggerCfg.EliminateSpaces = newCfg.EliminateSpaces;
triggerCfg.PrintCaption = newCfg.PrintCaption;
ApplyConfig();
}
}
};
}
#endregion Configuration Change Handling
/// <summary>
/// Writes the test cycle results into a file
/// Events:
/// Event.ResultsWritten
/// Event.Busy
/// </summary>
/// <param name="batch">Results to write into a file</param>
/// <returns>Reference to the operation</returns>
public IOperation ProcessResultsOp(Results.Entities.Batch batch)
{
this.batch = batch;
return this;
}
/// <summary>Start this operation</summary>
public void Start()
{
Process(batch);
}
/// <summary>Run this operation</summary>
/// <returns>Event.ResultsProcessed</returns>
public Event Run()
{
return Event.ResultsProcessed;
}
/// <summary>Stop this operation</summary>
public void Stop()
{
}
void Process(Results.Entities.Batch batch)
{
return;
}
}
}

View File

@ -1,170 +0,0 @@
///
/// Copyright (c) 2020 Sensus Slovensko a.s.
///
using System;
using System.Xml.Serialization;
using Config.Entities;
using TBF.BenchControl.Generic;
using TBF.Resources;
using System.Collections.Generic;
namespace TBF.BenchControl.Output.EventTriggers.Statistics
{
/// <summary>
/// Serializable configuration of Output.EventTriggers.Standard component.
/// </summary>
public class TriggerCfg : ComponentCfgBase, Generic.IComponentCfg, Config.Entities.IParamsProvider
{
public static XmlSerializer Serializer = XmlSerializer.FromTypes(new[] { typeof(TriggerCfg) })[0];
public override XmlSerializer GetSerializer() { return Serializer; }
public IComponentCfgCtrl GetControl() { return new Configs.ParamsProvider.ComponentCfgCtrl(this, null); }
///
/// Serialized parameters
///
public string EventSource;
public Culture Culture;
public bool EliminateSpaces;
public bool PrintCaption;
/// Private parameterless constructor invoked by all other (public) constructors
TriggerCfg() {}
public TriggerCfg(string name, IComponentFactory factory)
: this()
{
Name = name;
Factory = factory;
ParentName = string.Empty;
InitializeAll();
}
public string ComponentName { get { return Name; } }
public void InitializeAll()
{
EventSource = "Štatistiky výsledkov";
Culture = Culture.EN;
EliminateSpaces = false;
PrintCaption = false;
}
string[] paramNames = new string[]
{
"Event source",
"Culture",
"Eliminate spaces",
"Print caption",
};
public string ParamName(int i) { return paramNames[i]; }
public int ParamsCount() { return paramNames.Length; }
public IList<string> ParamValues(int i)
{
IList<string> listOfValues = new List<string>();
if (i == 1)
{
for (Culture cu = 0; cu < Culture.Count; cu++) listOfValues.Add(cu.ToString());
return listOfValues;
}
else if (i == 2)
{
listOfValues.Add(Strings.yes);
listOfValues.Add(Strings.no);
return listOfValues;
}
else
{
return null;
}
}
public string ToString(int i)
{
switch (i)
{
case -1: return string.Format("Name={0}, FNameFmt={1}, NoSpaces={2}", Name, EventSource, EliminateSpaces);
case 0: return EventSource;
case 1: return Culture.ToString();
case 2: return EliminateSpaces ? Strings.yes : Strings.no;
case 3: return PrintCaption ? Strings.yes : Strings.no;
default: return string.Empty;
}
}
public CfgUpdateFlags UpdateParam(int i, string strValue)
{
switch (i)
{
case 0: EventSource = strValue; return CfgUpdateFlags.RestartRqrd;
case 1:
for (Culture cu = 0; cu < Culture.Count; cu++)
{
if (strValue == cu.ToString())
{
if (Culture != cu)
{
Culture = cu;
return CfgUpdateFlags.RestartRqrd;
}
else
{
return CfgUpdateFlags.None;
}
}
}
return CfgUpdateFlags.Error;
case 2: EliminateSpaces = (strValue == Strings.yes); return CfgUpdateFlags.RestartRqrd;
case 3: PrintCaption = (strValue == Strings.yes); return CfgUpdateFlags.RestartRqrd;
default: return CfgUpdateFlags.None;
}
}
public bool ValidateParam(int i, string strValue, out string message)
{
message = string.Empty;
switch (i)
{
case 0: return true;
case 1:
for (Culture cu = 0; cu < Culture.Count; cu++)
{
if (strValue == cu.ToString()) return true;
}
break;
case 2:
case 3:
if (strValue == Strings.yes || strValue == Strings.no) return true;
break;
default:
message = "Invalid index";
return false;
}
message = ParamName(i) + " is invalid";
return false;
}
void CopyContentTo(TriggerCfg prms)
{
prms.EventSource = this.EventSource;
prms.Culture = this.Culture;
prms.EliminateSpaces = this.EliminateSpaces;
prms.PrintCaption = this.PrintCaption;
}
public Config.Entities.IParamsProvider Clone()
{
TriggerCfg pars = new TriggerCfg();
CopyContentTo(pars);
return pars;
}
public bool UpdateEmbeddedDbEntity()
{
return true; /// =OK, do nothing
}
}
}

View File

@ -1233,6 +1233,7 @@ namespace TBF.BenchControl.Sequences
string[] writers = (StateMachine.Procedure.ResultsWriter != null) ? StateMachine.Procedure.ResultsWriter.Split(new char[] { '~' }) : new string[0];
string[] printers = (StateMachine.Procedure.ResultsPrinter != null) ? StateMachine.Procedure.ResultsPrinter.Split(new char[] { '~' }) : new string[0];
string[] eventTriggers = (StateMachine.Procedure.EventTriggers != null) ? StateMachine.Procedure.EventTriggers.Split(new char[] { '~' }) : new string[0];
///
string[] rsltProcessors = new string[writers.Length + printers.Length + eventTriggers.Length];
writers.CopyTo(rsltProcessors, 0);
printers.CopyTo(rsltProcessors, writers.Length);
@ -1294,14 +1295,29 @@ namespace TBF.BenchControl.Sequences
ProcessData.BatchRslts.Batch.ProcedureName,
Program.LocalSettings.BatchNr);
evacuation:
/// Evacuation is similar to 'Abort session' (no results are saved), but the evacuation is done as well.
StateMachine.ControlBoard.ManualUIAllowed = true;
Event evacRetv = DoEvacuation(purgeEnd);
Bridge.OnProcedureCompleted(this, new ProcedureCompletedEventArgs(StateMachine.Procedure));
///
/// Process statistics (in each regular cycle after evacuation when ProcessData.StatisticsMonitoringComp is defined)
///
if (ProcessData.StatisticsMonitoringComp is IStatisticsMonitoring)
{
State.Create("MainSeq : Processing statistics")
.AddOperation((ProcessData.StatisticsMonitoringComp as IStatisticsMonitoring).ProcessStatisticsOp(ProcessData.BatchRslts.Batch.BatchNr))
.AddOperation(checkUiOp)
.EnterState();
do {
e = StateMachine.WaitRunDevsRunOps();
if (e.Contains(Event.UiCmdStop)) goto stop;
}
while (e.Contains(Event.Busy));
}
///
/// Procedure completed, branch depending on the result of evacuation
///
Bridge.OnProcedureCompleted(this, new ProcedureCompletedEventArgs(StateMachine.Procedure));
switch (evacRetv)
{
case Event.Error: goto error;

View File

@ -17,6 +17,7 @@ namespace TBF.BenchControl.Sequences
///
public static IBenchInfo BenchInfo;
public static IErrorFlags ErrorFlagsComp;
public static IStatisticsMonitoring StatisticsMonitoringComp;
public static Output.DB.SensusOracle.Database OracleDB;
///

View File

@ -232,6 +232,8 @@ namespace TBF.BenchControl
if (cmpnt is Elde.ControlBoardDev) ControlBoard = cmpnt as Elde.ControlBoardDev;
if (cmpnt is IBenchInfo) ProcessData.BenchInfo = cmpnt as IBenchInfo;
if (cmpnt is IErrorFlags) ProcessData.ErrorFlagsComp = cmpnt as IErrorFlags;
if (cmpnt is IStatisticsMonitoring) ProcessData.StatisticsMonitoringComp = cmpnt as IStatisticsMonitoring;
if ((cmpnt is Output.DB.SensusOracle.Database) && (ProcessData.OracleDB == null))
{
ProcessData.OracleDB = cmpnt as Output.DB.SensusOracle.Database;

View File

@ -133,7 +133,6 @@ namespace TBF.BenchControl
Factories.Add(new Output.DB.SensusOracle.Factory());
Factories.Add(new Output.EventTriggers.Iperl.Factory());
Factories.Add(new Output.EventTriggers.Standard.Factory());
Factories.Add(new Output.EventTriggers.Statistics.Factory());
Factories.Add(new Output.FileWriters.Basic.FactorySingle());
Factories.Add(new Output.FileWriters.Basic.FactoryCompound());
Factories.Add(new Output.FileWriters.Basic.FactoryHeatMeters());
@ -185,7 +184,8 @@ namespace TBF.BenchControl
Factories.Add(new Elde.ValveEx.ValveFactory());
Factories.Add(new Various.ErrorFlags.Factory());
Factories.Add(new Various.Evaporation.Factory());
Factories.Add(new Various.TankWithLevelMsrmnt.Factory());
Factories.Add(new Various.StatisticsMonitoring.Factory());
Factories.Add(new Various.TankWithLevelMsrmnt.Factory());
Factories.Add(new WaterMeters.Munich.WaterMeterFactory()); /// 'WaterMeters.Munich'
Factories.Add(new WaterMeters.WaterMeter.WaterMeterFactory()); /// 'WaterMeter'
}

View File

@ -0,0 +1,27 @@
///
/// Copyright (c) 2020 Sensus Slovensko a.s.
///
using System;
using System.Collections.Generic;
using TBF.BenchControl.Generic;
namespace TBF.BenchControl.Various.StatisticsMonitoring
{
public class Factory : IComponentFactory
{
public string ClassName { get { return this.GetType().Namespace.Substring(17); } }
public void ResetStaticProperties() { ProcessStatistics.ResetStaticProperties(); }
public IComponent DummyComponent() { return new ProcessStatistics(); }
public IComponent GetComponent(IComponentCfg cfg, IList<IComponent> components) { return new ProcessStatistics(cfg); }
public IComponentCfg DefaultConfig() { return new StatisticsCfg(this.GetType().Namespace.Substring(25), this); }
public IComponentCfg CmpntCfgFromCmpntEntity(Config.Entities.Component component)
{
return ComponentCfgBase.CreateFromDbEntity(StatisticsCfg.Serializer, component, this);;
}
}
}

View File

@ -0,0 +1,204 @@
///
/// Copyright (c) 2020 Sensus Slovensko a.s.
///
using System;
using System.Collections.Generic;
using log4net;
using NHibernate;
using Events.Entities;
using Results.Entities;
namespace TBF.BenchControl.Various.StatisticsMonitoring
{
public class ProcessStatistics : ComponentBase, IOperation, GenericDevices.IStatisticsMonitoring
{
private static readonly ILog log = LogManager.GetLogger(typeof(ProcessStatistics));
public override string ToString() { return string.Format("{0}({1})", ClassName, Cfg.ToString(1)); }
readonly StatisticsCfg statisticsCfg;
int lastBatchNr;
public ProcessStatistics() {}
public ProcessStatistics(Generic.IComponentCfg cfg)
: base(cfg)
{
statisticsCfg = cfg as StatisticsCfg;
ApplyConfig();
log.Debug(this.ToString());
}
void ApplyConfig()
{
}
#region Configuration Change Handling
public static void OnCfgChange(object sender, CfgChangeArgs args)
{
if (CfgChangeHandler == null) return;
try { CfgChangeHandler(sender, args); }
catch (Exception e) { log.Error("CfgChangeHandler(...) failed", e); }
}
public static event EventHandler<CfgChangeArgs> CfgChangeHandler;
public override void StartChangeHandler()
{
CfgChangeHandler += delegate(object sender, CfgChangeArgs args)
{
StatisticsCfg newCfg = args.Cfg as StatisticsCfg;
if (newCfg != null && newCfg.Name.Equals(Name))
{
if (args.Command == CfgChangeCmd.CfgChange)
{
statisticsCfg.EventSource = newCfg.EventSource;
statisticsCfg.iPerlHeadFailureRateThreshold = newCfg.iPerlHeadFailureRateThreshold;
ApplyConfig();
}
}
};
}
#endregion Configuration Change Handling
/// <summary>
/// Writes the test cycle results into a file
/// Events:
/// Event.StatisticsProcessed
/// Event.Busy
/// </summary>
/// <param name="batch">Results to write into a file</param>
/// <returns>Reference to the operation</returns>
public IOperation ProcessStatisticsOp(int lastBatchNr)
{
this.lastBatchNr = lastBatchNr;
return this;
}
public void Start()
{
Process(lastBatchNr, statisticsCfg);
}
public Event Run()
{
return Event.StatisticsProcessed;
}
public void Stop()
{
}
/// <summary>
/// Process recent batch results and calculate statistics of iPERL head failures
/// </summary>
/// <param name="batchNr">Number of the last saved batch</param>
void Process(int batchNr, StatisticsCfg statisticsCfg)
{
const int RequiredUsages = 10;
const int MaxBatches = 20;
float iperlHeadFailureRateThreshold = (float)statisticsCfg.iPerlHeadFailureRateThreshold / 100.0f;
int completeBatchesProcessed = 0;
int[] usages = new int[Config.Data.WMsCount];
int[] failures = new int[Config.Data.WMsCount];
for (int i = 0; i < Config.Data.WMsCount; i++) usages[i] = failures[i] = 0;
///
/// Read results of recent batches (up to 'MaxBatches')
/// Take into account only batches where the 1st test in named 'RFID' and
/// at least one water meter completed all tests.
///
try
{
ISession session = Results.DB.CreateSession();
int usagesMin;
do
{
usagesMin = 0;
IList<Batch> batches = session.QueryOver<Batch>()
.Where(x => x.Id == batchNr)
.List();
batchNr--;
if (batches.Count != 1 || batches[0].TestRslts.Count < 1 || batches[0].TestRslts[0].MethodClass != "TestMethods.iPerlCommunication")
{
continue;
}
bool isACompleteBatch = false;
foreach (var wm in batches[0].WaterMeters)
{
int i = wm.WMPosition - 1;
if (0 <= i && i < Config.Data.WMsCount && usages[i] < RequiredUsages && !wm.Disabled && wm.CompletedFromTests())
{
isACompleteBatch = true;
usages[i]++;
if (!wm.MeterTestRslts[0].Passed) failures[i]++;
}
}
usagesMin = int.MaxValue;
for (int i = 0; i < Config.Data.WMsCount; i++) if (usagesMin > usages[i]) usagesMin = usages[i];
if (isACompleteBatch) completeBatchesProcessed++;
}
while ((usagesMin < RequiredUsages) && (batchNr > 0) && (completeBatchesProcessed < MaxBatches));
}
catch (Exception exc)
{
log.ErrorFormat("Failed to calculate iPERL head usage statistics: {0}", exc.Message);
}
///
/// Find out whether at lest one event needs to be triggered
///
bool doTriggerEvents = false;
for (int i = 0; i < Config.Data.WMsCount; i++)
{
if ((usages[i] > 0) && (iperlHeadFailureRateThreshold > 0) && (float)failures[i] / (float)usages[i] >= iperlHeadFailureRateThreshold)
{
doTriggerEvents = true;
break;
}
}
if (doTriggerEvents)
{
///
/// Trigger events
///
try
{
ISession session = Events.DB.CreateSession();
Events.DB.LoadSubscribers(session);
for (int i = 0; i < Config.Data.WMsCount; i++)
{
if ((usages[i] > 0) && (iperlHeadFailureRateThreshold > 0) && (float)failures[i] / (float)usages[i] >= iperlHeadFailureRateThreshold)
{
TBF.UiBridge.Bridge.TriggerEvent(session,
statisticsCfg.EventSource,
EventClass.EquipmentHW,
Severity.Error,
string.Format("Príliš veľa chýb hlavice č. {0}", i + 1),
string.Format("Percento chýb je {0}%", (100 * failures[i]) / usages[i]),
SubscriberGroup.Metrology | SubscriberGroup.Maintenance | SubscriberGroup.Production);
}
}
}
catch (Exception exc)
{
log.ErrorFormat("Failed to trigger events: source = {0}, message = {1}", statisticsCfg.EventSource, exc.Message);
}
}
}
}
}

View File

@ -0,0 +1,127 @@
///
/// Copyright (c) 2020 Sensus Slovensko a.s.
///
using System;
using System.Xml.Serialization;
using Config.Entities;
using TBF.BenchControl.Generic;
using TBF.Resources;
using System.Collections.Generic;
namespace TBF.BenchControl.Various.StatisticsMonitoring
{
/// <summary>
/// Serializable configuration of Various.StatisticsMonitoring component.
/// </summary>
public class StatisticsCfg : ComponentCfgBase, Generic.IComponentCfg, Config.Entities.IParamsProvider
{
public static XmlSerializer Serializer = XmlSerializer.FromTypes(new[] { typeof(StatisticsCfg) })[0];
public override XmlSerializer GetSerializer() { return Serializer; }
public IComponentCfgCtrl GetControl() { return new Configs.ParamsProvider.ComponentCfgCtrl(this, null); }
///
/// Serialized parameters
///
public string EventSource;
public int iPerlHeadFailureRateThreshold; /// 0 = off, 1..100% event is triggered when percentage reaches this level
/// Private parameterless constructor invoked by all other (public) constructors
StatisticsCfg() { }
public StatisticsCfg(string name, IComponentFactory factory)
: this()
{
Name = name;
Factory = factory;
ParentName = string.Empty;
InitializeAll();
}
public string ComponentName { get { return Name; } }
public void InitializeAll()
{
EventSource = "Štatistiky"; /// 0
iPerlHeadFailureRateThreshold = 20; /// 1
}
string[] paramNames = new string[]
{
"Event source", /// 0
"Threshold for iPERL head failure rate [%] (0=off)", /// 1
};
public string ParamName(int i) { return paramNames[i]; }
public int ParamsCount() { return paramNames.Length; }
public IList<string> ParamValues(int i)
{
return null;
}
public string ToString(int i)
{
switch (i)
{
case -1: return string.Format("Name={0}, EventSource={1}, FailureRatePct={2}, ...", Name, EventSource, iPerlHeadFailureRateThreshold);
case 0: return EventSource;
case 1: return iPerlHeadFailureRateThreshold.ToString();
default: return string.Empty;
}
}
public CfgUpdateFlags UpdateParam(int i, string strValue)
{
switch (i)
{
case 0: EventSource = strValue; return CfgUpdateFlags.AnyChange;
case 1: iPerlHeadFailureRateThreshold = int.Parse(strValue); return CfgUpdateFlags.AnyChange;
default: return CfgUpdateFlags.None;
}
}
/// <summary>
/// Validate string form of a parameter value
/// </summary>
/// <param name="i">Parameter index</param>
/// <param name="strValue">String form of a parameter</param>
/// <param name="message">Message in case value is not valid</param>
/// <returns>true when string form of a parameter is OK</returns>
public bool ValidateParam(int i, string strValue, out string message)
{
message = string.Empty;
int percentage;
switch (i)
{
case 0:
return true;
case 1:
if (int.TryParse(strValue, out percentage) && (0 <= percentage) && (percentage <= 100)) return true;
message = "Threshold for iPERL head failure rate in % (0 = off)";
return false;
default:
message = "Invalid index";
return false;
}
}
void CopyContentTo(StatisticsCfg prms)
{
prms.EventSource = this.EventSource; /// 0
prms.iPerlHeadFailureRateThreshold = this.iPerlHeadFailureRateThreshold; /// 1
}
public Config.Entities.IParamsProvider Clone()
{
StatisticsCfg pars = new StatisticsCfg();
CopyContentTo(pars);
return pars;
}
public bool UpdateEmbeddedDbEntity()
{
return true; /// =OK, do nothing
}
}
}

View File

@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
// Build Number
// Revision
//
[assembly: AssemblyVersion("2.26.1457.0")]
[assembly: AssemblyFileVersion("2.26.1457.0")]
[assembly: AssemblyVersion("2.26.1458.0")]
[assembly: AssemblyFileVersion("2.26.1458.0")]

View File

@ -626,6 +626,7 @@
<Compile Include="BenchControl\GenericDevices\ISequenceCondition.cs" />
<Compile Include="BenchControl\GenericDevices\ISimultTestMethod.cs" />
<Compile Include="BenchControl\GenericDevices\IDatastreamReader.cs" />
<Compile Include="BenchControl\GenericDevices\IStatisticsMonitoring.cs" />
<Compile Include="BenchControl\GenericDevices\ITankDraining.cs" />
<Compile Include="BenchControl\GenericDevices\ITankDrainingCfg.cs" />
<Compile Include="BenchControl\GenericDevices\ITestMethodWith2ndPass.cs" />
@ -909,9 +910,6 @@
<Compile Include="BenchControl\Output\EventTriggers\Iperl\Factory.cs" />
<Compile Include="BenchControl\Output\EventTriggers\Iperl\Trigger.cs" />
<Compile Include="BenchControl\Output\EventTriggers\Iperl\TriggerCfg.cs" />
<Compile Include="BenchControl\Output\EventTriggers\Statistics\Factory.cs" />
<Compile Include="BenchControl\Output\EventTriggers\Statistics\Trigger.cs" />
<Compile Include="BenchControl\Output\EventTriggers\Statistics\TriggerCfg.cs" />
<Compile Include="BenchControl\Output\EventTriggers\Standard\Factory.cs" />
<Compile Include="BenchControl\Output\EventTriggers\Standard\Trigger.cs" />
<Compile Include="BenchControl\Output\EventTriggers\Standard\TriggerCfg.cs" />
@ -1585,6 +1583,9 @@
<Compile Include="BenchControl\Various\ManualLevelMsrmnt\WaterLevelForm.designer.cs">
<DependentUpon>WaterLevelForm.cs</DependentUpon>
</Compile>
<Compile Include="BenchControl\Various\StatisticsMonitoring\Factory.cs" />
<Compile Include="BenchControl\Various\StatisticsMonitoring\ProcessStatistics.cs" />
<Compile Include="BenchControl\Various\StatisticsMonitoring\StatisticsCfg.cs" />
<Compile Include="BenchControl\Various\TankWithLevelMsrmnt\Factory.cs" />
<Compile Include="BenchControl\Various\TankWithLevelMsrmnt\Tank.cs" />
<Compile Include="BenchControl\Various\TankWithLevelMsrmnt\TankCfg.cs" />