849 lines
36 KiB
C#
849 lines
36 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using log4net;
|
|
using TBF.BenchControl.GenericDevices;
|
|
using TBF.BenchControl.Operations;
|
|
using TBF.Boxes;
|
|
using TBF.Resources;
|
|
using TBF.UiBridge;
|
|
|
|
namespace TBF.BenchControl.Sequences
|
|
{
|
|
/// <summary>
|
|
/// Sequence is a group of states that can be dynamically added to
|
|
/// and removed from the state machine
|
|
/// </summary>
|
|
public class SequenceBase
|
|
{
|
|
private static readonly ILog log = LogManager.GetLogger(typeof(SequenceBase));
|
|
protected static readonly ILog processDataLogger = LogManager.GetLogger("ProcessData");
|
|
protected static readonly ILog allResults = LogManager.GetLogger("AllResults");
|
|
protected static readonly ILog summaryResults = LogManager.GetLogger("SummaryResults");
|
|
|
|
///------------------------------------------------------------
|
|
/// Global static variables set only once.
|
|
///------------------------------------------------------------
|
|
public static BenchId.Component BenchId;
|
|
public static IList<IFlowMeter> FlowMeters; /// list of reference flowmeters
|
|
public static IList<IRegulValve> RegulValves; /// list of regulation valves
|
|
public static IList<IPumpFM> PumpsWithFM; /// list of FM controlled pumps
|
|
public static IList<IWaterMeter> WaterMeters; /// list of water meters
|
|
public static IList<ICamera> Cameras; /// list of cameras
|
|
|
|
///------------------------------------------------------------
|
|
/// Procedure related (static) variables.
|
|
/// They are re-initialized when LoadProcedure() is called
|
|
///------------------------------------------------------------
|
|
protected static IList<Entities.TestResult> results;
|
|
public static int ReferenceFlowmetersCount;
|
|
public static float[] LtrPerRefPulse; /// Reference flowmeter coefficients
|
|
public static float Qrise;
|
|
public static float Qfall;
|
|
|
|
/// <summary>
|
|
/// Clear all test results.
|
|
/// </summary>
|
|
protected static void ResetResults()
|
|
{
|
|
results = new List<Entities.TestResult>();
|
|
Qrise = 0;
|
|
Qfall = 0;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Add result to the list of results.
|
|
/// Overwrite (=delete) any previous result with the same name.
|
|
/// </summary>
|
|
/// <param name="newTestResult">New test result</param>
|
|
protected static void AddOrOverwriteResult(Entities.TestResult newTestResult)
|
|
{
|
|
Entities.TestResult toDelete =
|
|
results.FirstOrDefault<Entities.TestResult>(x => x.Name.Equals(newTestResult.Name) &&
|
|
(x.Part == newTestResult.Part) &&
|
|
(x.TestId == newTestResult.TestId));
|
|
if (toDelete != null) results.Remove(toDelete);
|
|
|
|
results.Add(newTestResult);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Check whether the results are complete, whether there is a result for each test.
|
|
/// </summary>
|
|
/// <param name="tests">All tests</param>
|
|
/// <returns>true = The results are complete</returns>
|
|
protected static bool ResultsAreComplete(IList<Entities.Test> tests)
|
|
{
|
|
foreach (var test in tests)
|
|
{
|
|
if (!test.Method.Contains("RoiDetection")) /// TODO: Use 'DoNotEvaluate' etc.
|
|
{
|
|
for (int r = 1; r <= test.Repeats; r++)
|
|
{
|
|
bool resultExists = false;
|
|
foreach (var tr in results)
|
|
{
|
|
if ((tr.DoNotEvaluate == false) && (tr.RepetitionNr == r) && (tr.TestName == test.Name))
|
|
{
|
|
resultExists = true;
|
|
break;
|
|
}
|
|
}
|
|
if (!resultExists) return false;
|
|
}
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
protected static float TimeEstimateTotal; /// Time estimate of the selected cycle or test
|
|
protected static float TimeEstimateBeginRpts; /// Time estimate at the beginning of all repetitions of the current tests
|
|
protected static float TimeEstimateOneTest; /// Time estimate of the current test (one repetition)
|
|
|
|
protected static bool cycleBeginFormOpened;
|
|
|
|
static SequenceBase()
|
|
{
|
|
results = new List<Entities.TestResult>();
|
|
|
|
WMVolumes = new FloatBox[Program.WMsCount];
|
|
WMErrors = new FloatBox[Program.WMsCount];
|
|
for (int i = 0; i < Program.WMsCount; i++)
|
|
{
|
|
WMVolumes[i] = new FloatBox() { Name = string.Format("Volume{0}", i), Format = "F2" };
|
|
WMErrors[i] = new FloatBox() { Name = string.Format("Error{0}", i), Format = "F2" };
|
|
}
|
|
|
|
cycleBeginFormOpened = false;
|
|
}
|
|
|
|
///------------------------------------------------------------
|
|
/// Test related (instance) variables.
|
|
/// Created when test sequence is open.
|
|
/// They persist during all repetitions of the same test
|
|
///------------------------------------------------------------
|
|
protected static BenchControl.FeedingPath inPath;
|
|
protected static BenchControl.BenchPath benchPath;
|
|
protected static BenchControl.OutputPath outPath;
|
|
protected static BenchControl.MetersPath sensPath;
|
|
protected static Entities.TransitionSequence transitionStart;
|
|
protected static Entities.TransitionSequence transitionStop;
|
|
|
|
|
|
#region Temperature_Pressure_Humidity
|
|
|
|
protected static FloatBox tempIn = new FloatBox() { Name = "Temperature In", Format = "F2" };
|
|
protected static FloatBox tempOut = new FloatBox() { Name = "Temperature Out", Format = "F2" };
|
|
protected static FloatBox tempDiv = new FloatBox() { Name = "Temperature Div", Format = "F2" };
|
|
protected static FloatBox pressIn = new FloatBox() { Name = "Pressure In", Format = "F3", Factor = 0.01f };
|
|
protected static FloatBox pressOut = new FloatBox() { Name = "Pressure Out", Format = "F3", Factor = 0.01f };
|
|
protected static FloatBox airTemperature = new FloatBox() { Name = "Ambient Temperature", Format = "F1" };
|
|
protected static FloatBox airPressure = new FloatBox() { Name = "Ambient Pressure", Format = "F1" };
|
|
protected static FloatBox airHumidity = new FloatBox() { Name = "Ambient Humidity", Format = "F1" };
|
|
///
|
|
protected float tempInSum;
|
|
protected float tempOutSum;
|
|
protected float tempDivSum;
|
|
protected float pressInSum;
|
|
protected float pressOutSum;
|
|
protected float ambientTempSum;
|
|
protected float ambientPressSum;
|
|
protected float ambientHumiSum;
|
|
///
|
|
protected int averagedDataCount;
|
|
///
|
|
protected void ResetAveragedData()
|
|
{
|
|
tempInSum = 0;
|
|
tempOutSum = 0;
|
|
tempDivSum = 0;
|
|
pressInSum = 0;
|
|
pressOutSum = 0;
|
|
ambientTempSum = 0;
|
|
ambientPressSum = 0;
|
|
ambientHumiSum = 0;
|
|
///
|
|
averagedDataCount = 0;
|
|
}
|
|
///
|
|
protected void AccumulateAveragedData()
|
|
{
|
|
tempInSum += tempIn.Val;
|
|
tempOutSum += tempOut.Val;
|
|
tempDivSum += tempDiv.Val;
|
|
pressInSum += pressIn.Val;
|
|
pressOutSum += pressOut.Val;
|
|
ambientTempSum += airTemperature.Val;
|
|
ambientPressSum += airPressure.Val;
|
|
ambientHumiSum += airHumidity.Val;
|
|
///
|
|
averagedDataCount++;
|
|
}
|
|
///
|
|
protected void UpdateTestRsltWithAveragedData(Entities.TestResult tstRslt)
|
|
{
|
|
if (averagedDataCount != 0)
|
|
{
|
|
float denominator = (float)averagedDataCount;
|
|
tstRslt.AmbientTempAve = ambientTempSum / denominator;
|
|
tstRslt.AmbientPressAve = ambientPressSum / denominator;
|
|
tstRslt.AmbientHumiAve = ambientHumiSum / denominator;
|
|
tstRslt.PressInAvrg = pressInSum / denominator;
|
|
tstRslt.PressOutAvrg = pressOutSum / denominator;
|
|
tstRslt.TempInAvrg = tempInSum / denominator;
|
|
tstRslt.TempOutAvrg = tempOutSum / denominator;
|
|
tstRslt.TempDivAvrg = tempDivSum / denominator;
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
protected float ltrPerRefPulse;
|
|
|
|
protected IOperation readRegisters1;
|
|
protected IOperation readRegisters2;
|
|
protected IOperation queryEnd1;
|
|
protected IOperation queryEnd2;
|
|
protected IOperation checkUiOp;
|
|
|
|
protected IOperation processDataLoggingOp;
|
|
|
|
protected bool ticTac = false;
|
|
protected int[] WMPulses = new int[Program.WMsCount];
|
|
protected int[] WMRefPulses = new int[Program.WMsCount];
|
|
|
|
protected static FloatBox[] WMVolumes;
|
|
protected static FloatBox[] WMErrors;
|
|
|
|
protected static IntBox refCount = new IntBox() { Name = "RefCount" };
|
|
protected static FloatBox refFreq = new FloatBox() { Name = "RefFreq", Format = "F2" };
|
|
protected static FloatBox refFlow = new FloatBox() { Name = "RefFlow", Format = "F2" };
|
|
protected static FloatBox mass = new FloatBox() { Name = "Mass", Format = "F1" };
|
|
protected static FloatBox startMass = new FloatBox() { Name = "Start Mass", Format = "F1" };
|
|
protected static FloatBox endMass = new FloatBox() { Name = "End Mass", Format = "F1" };
|
|
|
|
/// <summary>
|
|
/// To clear process values at the beginning of each test
|
|
/// </summary>
|
|
protected void ClearProcessValues()
|
|
{
|
|
//if (WMPulses != null) { for (int i = 0; i < WMPulses.Length; i++) WMPulses[i] = 0; }
|
|
//if (WMRefPulses != null) { for (int i = 0; i < WMRefPulses.Length; i++) WMPulses[i] = 0; }
|
|
|
|
for (int i = 0; i < Program.WMsCount; i++)
|
|
{
|
|
WMPulses[i] = 0;
|
|
WMPulses[i] = 0;
|
|
WMVolumes[i].Clear();
|
|
WMErrors[i].Clear();
|
|
}
|
|
|
|
refCount.Clear();
|
|
refFreq.Clear();
|
|
refFlow.Clear();
|
|
mass.Clear();
|
|
startMass.Clear();
|
|
endMass.Clear();
|
|
}
|
|
|
|
|
|
///
|
|
/// Process data logging
|
|
///
|
|
public void LogProcessHeader(ILog logger)
|
|
{
|
|
LogProcessHeader(logger, null);
|
|
}
|
|
|
|
public void LogProcessHeader(ILog logger, string sectionName)
|
|
{
|
|
logger.Info(Environment.NewLine);
|
|
if (sectionName != null) logger.Info(sectionName);
|
|
logger.Info("Time Flow TstTime Ref.cnt Ref.vol Tin Tout Tdiv Pin Pout Mass VolMM Tamb Hamb Pamb Rv");
|
|
logger.Info(Environment.NewLine);
|
|
}
|
|
|
|
public void LogProcessData(ILog logger)
|
|
{
|
|
logger.InfoFormat("{0} {1} {2} {3} {4} {5} {6} {7} {8} {9} {10} {11} {12} {13} {14} {15}",
|
|
DateTime.Now.ToLongTimeString(),
|
|
Utils.FloatToStr(refFlow.Val, 4),
|
|
StateMachine.ControlBoard.TTime.ToString("F3"),
|
|
StateMachine.ControlBoard.EtPulses(0),
|
|
Formulas.VolumeFromPulses(StateMachine.ControlBoard.EtPulses(0), 1.0f / ltrPerRefPulse).ToString("F3"),
|
|
tempIn,
|
|
tempOut,
|
|
tempDiv,
|
|
pressIn,
|
|
pressOut,
|
|
mass,
|
|
"VolMM",
|
|
airTemperature,
|
|
airHumidity,
|
|
airPressure,
|
|
outPath.RegulValve.Position.ToString("F1"));
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Empties the tank: opens the emptying valve and measures the weight.
|
|
/// </summary>
|
|
/// <param name="EmptyTankValve">Valve to empty the tank</param>
|
|
/// <param name="Balance">Balance underneath the tank</param>
|
|
/// <returns>Event.Done or Event.Error</returns>
|
|
protected Event EmptyTheTank(IValve EmptyTankValve, IBalance Balance)
|
|
{
|
|
//------------------------------------------------
|
|
Bridge.OnActivity(this, TBF.Resources.Strings.Emptying_tank);
|
|
//------------------------------------------------
|
|
|
|
IList<Event> e;
|
|
Bridge.Bench2UI(ButtonsEtc.StopBtnEn);
|
|
|
|
State.Create("SequenceBase : Opening the emptying valve")
|
|
.AddOperation(checkUiOp)
|
|
.AddOperation(StateMachine.ControlBoard.SetValvesOp(EmptyTankValve, null))
|
|
.EnterState();
|
|
do { e = StateMachine.WaitRunDevsRunOps(); }
|
|
while (!e.Contains(Event.ValvesSet));
|
|
|
|
do
|
|
{
|
|
//--------------------------------
|
|
State.Create("SequenceBase : Emptying the tank")
|
|
.AddOperation(checkUiOp)
|
|
.AddOperation(Balance.ReadMassOp(ref mass))
|
|
.AddOperation(StateMachine.ControlBoard.UpdateTankWeightOp())
|
|
.EnterState();
|
|
do
|
|
{
|
|
e = StateMachine.WaitRunDevsRunOps();
|
|
if (e.Contains(Event.Error)) return Event.Error;
|
|
if (e.Contains(Event.UiCmdStop)) goto quit_emptying;
|
|
if (e.Contains(Event.BalanceOverload)) { }; /// Tank should be emptying now
|
|
}
|
|
while (!e.Contains(Event.BalanceDone));
|
|
}
|
|
while (!Balance.IsEmpty(mass.Val));
|
|
|
|
quit_emptying:
|
|
//--------------------------------
|
|
State.Create("SequenceBase : Closing the emptying valve")
|
|
.AddOperation(checkUiOp)
|
|
.AddOperation(Balance.ReadMassOp(ref mass))
|
|
.AddOperation(StateMachine.ControlBoard.UpdateTankWeightOp())
|
|
.AddOperation(StateMachine.ControlBoard.SetValvesOp(null, EmptyTankValve))
|
|
.EnterState();
|
|
do
|
|
{
|
|
e = StateMachine.WaitRunDevsRunOps();
|
|
if (e.Contains(Event.Error)) return Event.Error;
|
|
}
|
|
while (!e.Contains(Event.ValvesSet) || !e.Contains(Event.BalanceDone));
|
|
|
|
State.Create("SequenceBase : Updating the weight")
|
|
.AddOperation(checkUiOp)
|
|
.AddOperation(Balance.ReadMassOp(ref mass))
|
|
.AddOperation(new Operations.TimerOp(5))
|
|
.AddOperation(StateMachine.ControlBoard.UpdateTankWeightOp())
|
|
.EnterState();
|
|
do
|
|
{
|
|
e = StateMachine.WaitRunDevsRunOps();
|
|
if (e.Contains(Event.Error)) return Event.Error;
|
|
}
|
|
while (!e.Contains(Event.BalanceDone) || !e.Contains(Event.TimerExpired));
|
|
|
|
return Event.Done;
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Passed as an argument to Transition(sequence, context)
|
|
/// </summary>
|
|
public enum TransitionContext
|
|
{
|
|
PurgeBegin,
|
|
PurgeEnd,
|
|
TestStart,
|
|
TestEnd,
|
|
}
|
|
|
|
/// <summary>
|
|
/// Executes steps of a transition sequence
|
|
/// </summary>
|
|
/// <param name="transitionSequence">TransitionSequence entity</param>
|
|
/// <param name="context">Calling context (see above)</param>
|
|
/// <returns>
|
|
/// Event.Done Transition sequence completed OK
|
|
/// Event.UiCmdStop Transition sequence interrupted by the STOP on-screen button
|
|
/// Event.Error Error (e.g. RegulValveTimeOut returned by Run() of SetRegulValvePositionOp)
|
|
/// </returns>
|
|
protected Event Transition(Entities.TransitionSequence transitionSequence, TransitionContext context)
|
|
{
|
|
IList<Event> e;
|
|
|
|
string message;
|
|
switch (context)
|
|
{
|
|
case TransitionContext.PurgeBegin: message = Strings.Purging_i_n; break;
|
|
case TransitionContext.PurgeEnd: message = Strings.Emptying_i_n; break;
|
|
case TransitionContext.TestStart: message = Strings.Test_start_sequence_i_n; break;
|
|
case TransitionContext.TestEnd: message = Strings.Test_stop_sequence_i_n; break;
|
|
default: message = "Transition"; break;
|
|
}
|
|
|
|
if (transitionSequence == null)
|
|
{
|
|
///
|
|
/// No transition sequence defined --> Default action
|
|
///
|
|
if (context == TransitionContext.TestStart)
|
|
{
|
|
State.Create("SequenceBase : Transition : TestStart - Default action")
|
|
.AddOperation(checkUiOp).AddOperation(StateMachine.ControlBoard
|
|
.SetValvesOp(GenericDevices.ValveBase.Merge(inPath.ValvesOpen, benchPath.ValvesOpen, outPath.ValvesOpen),
|
|
GenericDevices.ValveBase.Merge(inPath.ValvesClose, benchPath.ValvesClose, outPath.ValvesClose)))
|
|
.EnterState();
|
|
do
|
|
{
|
|
e = StateMachine.WaitRunDevsRunOps();
|
|
if (e.Contains(Event.UiCmdStop)) return Event.UiCmdStop;
|
|
}
|
|
while (e.Contains(Event.ValvesBusy));
|
|
}
|
|
else if (context == TransitionContext.TestEnd)
|
|
{
|
|
State.Create("SequenceBase : Transition : TestEnd - Default action")
|
|
.AddOperation(checkUiOp).AddOperation(StateMachine.ControlBoard
|
|
.SetValvesOp(StateMachine.DefaultValvesOpen, StateMachine.DefaultValvesClose))
|
|
.EnterState();
|
|
do {
|
|
e = StateMachine.WaitRunDevsRunOps();
|
|
if (e.Contains(Event.UiCmdStop)) return Event.UiCmdStop;
|
|
}
|
|
while (!e.Contains(Event.ValvesSet));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
///
|
|
/// Execute the transition sequence
|
|
///
|
|
IList<Entities.TransitionStep> transitionSteps = StateMachine.WtSession
|
|
.CreateQuery("FROM TransitionStep WHERE TransitionSequence = :tsId ORDER BY ItemNr")
|
|
.SetParameter("tsId", transitionSequence.Id)
|
|
.List<Entities.TransitionStep>();
|
|
|
|
int stepsCount = transitionSteps.Count;
|
|
foreach (var step in transitionSteps)
|
|
{
|
|
//------------------------------------------------
|
|
Bridge.OnActivity(this, string.Format(message, transitionSequence.Name, step.ItemNr + 1, stepsCount));
|
|
Bridge.OnMessage(this, step.Message);
|
|
//------------------------------------------------
|
|
|
|
/// FM controlled pumps are canged imediately without using any state operations
|
|
float[] allFMPumpPcts = Utils.GetPumpWithFMPcts(step);
|
|
for (int i = 0; i < allFMPumpPcts.Length; i++)
|
|
{
|
|
float pwr = allFMPumpPcts[i];
|
|
if (pwr > 0) /// Negative value means no power change
|
|
{
|
|
PumpsWithFM[i].TurnOn(pwr);
|
|
}
|
|
else if (pwr == 0)
|
|
{
|
|
PumpsWithFM[i].TurnOff();
|
|
}
|
|
}
|
|
|
|
/// Get new regulation valve positions,
|
|
float[] allRegvPositions = Utils.GetRegulValvesPositions(step);
|
|
|
|
/// Prepare necessary SetRegValvePositionOp operations for RV-s with changed positions
|
|
IList<IOperation> rvPosOps = new List<IOperation>();
|
|
for (int i = 0; i < allRegvPositions.Length; i++)
|
|
{
|
|
if (allRegvPositions[i] >= 0) /// Negative value means no position change
|
|
{
|
|
rvPosOps.Add(RegulValves[i]
|
|
.SetRegulValvePositionOp(Math.Max(0, allRegvPositions[i] - 0.05f),
|
|
Math.Min(100.0f, allRegvPositions[i] + 0.05f), 60));
|
|
}
|
|
}
|
|
|
|
/// Max. one SetRegulValvePositionOp can be started or stopped in one sub-step.
|
|
/// Therefore SetRegulValvePositionOp operations are added and removed to subsequent states one by one.
|
|
int delay = Math.Max(2, step.Duration - rvPosOps.Count + 2);
|
|
bool stopFlag = false;
|
|
bool errorFlag = false;
|
|
|
|
///
|
|
int lastStartedRV = -1;
|
|
for (int i = 0; i < rvPosOps.Count; i++)
|
|
{
|
|
State stepStrt = State.Create(string.Format("SequenceBase.Transition() : Step {0}", step.ItemNr + 1))
|
|
.AddOperation(checkUiOp)
|
|
.AddOperation(StateMachine.ControlBoard.SetValvesOp(Utils.ValvesOpen(step), Utils.ValvesClose(step)));
|
|
for (int j = 0; j <= i; j++) stepStrt.AddOperation(rvPosOps[j]);
|
|
lastStartedRV = i;
|
|
stepStrt.EnterState();
|
|
e = StateMachine.WaitRunDevsRunOps();
|
|
if (e.Contains(Event.Error) || e.Contains(Event.RegulValveTimeOut)) { errorFlag = true; break; }
|
|
if (e.Contains(Event.UiCmdStop)) { stopFlag = true; break; }
|
|
}
|
|
/// Max. valaue of lastStartedRV after exitting the loop is (rvPosOps.Count - 1)
|
|
|
|
if (!(stopFlag || errorFlag))
|
|
{
|
|
State stepDelay = State.Create(string.Format("SequenceBase.Transition() : Step {0}", step.ItemNr + 1))
|
|
.AddOperation(checkUiOp)
|
|
.AddOperation(StateMachine.ControlBoard.SetValvesOp(Utils.ValvesOpen(step), Utils.ValvesClose(step)))
|
|
.AddOperation(new TimerOp(delay));
|
|
for (int j = 0; j <= lastStartedRV; j++) stepDelay.AddOperation(rvPosOps[j]);
|
|
stepDelay.EnterState();
|
|
do
|
|
{
|
|
e = StateMachine.WaitRunDevsRunOps();
|
|
if (e.Contains(Event.Error) || e.Contains(Event.RegulValveTimeOut)) { errorFlag = true; break; }
|
|
if (e.Contains(Event.UiCmdStop)) { stopFlag = true; break; }
|
|
}
|
|
while (e.Contains(Event.TimerBusy) || e.Contains(Event.ValvesBusy));
|
|
}
|
|
|
|
for (int first = 1; first <= lastStartedRV; first++)
|
|
{
|
|
State stepStop = State.Create(string.Format("SequenceBase.Transition() : Step {0}", step.ItemNr + 1))
|
|
.AddOperation(checkUiOp)
|
|
.AddOperation(StateMachine.ControlBoard.SetValvesOp(Utils.ValvesOpen(step), Utils.ValvesClose(step)));
|
|
for (int j = first; j <= lastStartedRV; j++) stepStop.AddOperation(rvPosOps[j]);
|
|
stepStop.EnterState();
|
|
e = StateMachine.WaitRunDevsRunOps();
|
|
if (e.Contains(Event.Error) || e.Contains(Event.RegulValveTimeOut)) { errorFlag = true; }
|
|
if (e.Contains(Event.UiCmdStop)) { stopFlag = true; }
|
|
}
|
|
|
|
if (errorFlag) return Event.Error;
|
|
if (stopFlag) return Event.UiCmdStop;
|
|
}
|
|
}
|
|
|
|
if (context == TransitionContext.TestEnd)
|
|
{
|
|
///
|
|
/// Stop the pump at the end of test
|
|
///
|
|
foreach (var fmPump in PumpsWithFM) fmPump.TurnOff();
|
|
State.Create("SequenceBase : Test(s) completed -> Stopping the pump")
|
|
.AddOperation(checkUiOp)
|
|
.AddOperation((inPath.Pump is GenericDevices.IPumpFM) ? (inPath.Pump as GenericDevices.IPumpFM).TurnOffOp() : null)
|
|
.AddOperation(StateMachine.ControlBoard.SetValvesOp(null, inPath.Pump))
|
|
.AddOperation(StateMachine.ControlBoard.UpdateTankWeightOp())
|
|
.EnterState();
|
|
do
|
|
{
|
|
e = StateMachine.WaitRunDevsRunOps();
|
|
if (e.Contains(Event.Error)) return Event.Error;
|
|
}
|
|
while (!e.Contains(Event.ValvesSet) || ((inPath.Pump is GenericDevices.IPumpFM) && !e.Contains(Event.TurnPumpOnOffDone)));
|
|
}
|
|
|
|
return Event.Done;
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Opens a modeless dialog for entering data at the beginning of a procedure (serial numbers)
|
|
/// </summary>
|
|
/// <returns>false = OK, true = stop pressed</returns>
|
|
protected bool OpenCycleBeginForm()
|
|
{
|
|
IList<Event> e;
|
|
GenericDevices.IDataEntry dataEntryCmpnt =
|
|
TbfComponents.FindComponent(StateMachine.Procedure.DataEntry) as GenericDevices.IDataEntry;
|
|
if (dataEntryCmpnt is IHasCycleBeginForm)
|
|
{
|
|
Bridge.OnActivity(this, "Enter the water meter data");
|
|
State.Create("MainSeq : Enter begin data")
|
|
.AddPermanentOperation((dataEntryCmpnt as IHasCycleBeginForm).ShowCycleBeginFormOp(WaterMeters))
|
|
.AddOperation(checkUiOp)
|
|
.EnterState();
|
|
e = StateMachine.WaitRunDevsRunOps();
|
|
if (e.Contains(Event.UiCmdStop)) return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Waits until a modeless dialog for entering data at the beginnig of a procedure is closed.
|
|
/// This function is typically called at the end of the first test of the procedure.
|
|
/// </summary>
|
|
/// <returns>false = OK, true = stop pressed</returns>
|
|
protected bool CloseCycleBeginForm()
|
|
{
|
|
IList<Event> e;
|
|
GenericDevices.IDataEntry dataEntryCmpnt =
|
|
TbfComponents.FindComponent(StateMachine.Procedure.DataEntry) as GenericDevices.IDataEntry;
|
|
if (dataEntryCmpnt as IHasCycleBeginForm != null)
|
|
{
|
|
if (!State.LastEvents.Contains(Event.ModelessFormClosed))
|
|
{
|
|
/// Wait until modeless dialg is closed
|
|
State.Create("MainSeq : Check whether the entry form is closed")
|
|
.AddOperation(checkUiOp)
|
|
.EnterState();
|
|
do
|
|
{
|
|
e = StateMachine.WaitRunDevsRunOps();
|
|
if (e.Contains(Event.UiCmdStop)) return true;
|
|
}
|
|
while (!e.Contains(Event.ModelessFormClosed));
|
|
}
|
|
|
|
/// A state without any dataEntryCmpnt operation so that Stop() when entering
|
|
/// this state and Start() when entering the following state are executed.
|
|
State.Create("MainSeq : Nothing")
|
|
.AddOperation(checkUiOp)
|
|
.RemovePermanentOperation(dataEntryCmpnt as IOperation)
|
|
.EnterState();
|
|
e = StateMachine.WaitRunDevsRunOps();
|
|
if (e.Contains(Event.UiCmdStop)) return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Main loop where measurements are collected.
|
|
/// </summary>
|
|
/// <param name="realTest">false = a flow setting or a switching flow detection, true = measurement</param>
|
|
/// <returns>Event.MeasurementCompleted, Event.UiCmdStop, Event.Error or Event.Done</returns>
|
|
protected Event ReadRegistersTempPressAmbient(IList<IOperation> measureOperations, bool realTest)
|
|
{
|
|
IList<Event> e;
|
|
ticTac = !ticTac;
|
|
State.Create("Read water meters")
|
|
.AddOperation(checkUiOp)
|
|
.AddOperations(measureOperations)
|
|
.AddOperation(ticTac ? readRegisters1 : readRegisters2)
|
|
.AddOperation(benchPath.TempIn.ReadTempOp(ref tempIn))
|
|
.AddOperation(benchPath.TempOut.ReadTempOp(ref tempOut))
|
|
.AddOperation(outPath.TempDiv.ReadTempOp(ref tempDiv))
|
|
.AddOperation(benchPath.PressIn.ReadPressureOp(ref pressIn))
|
|
.AddOperation(benchPath.PressOut.ReadPressureOp(ref pressOut))
|
|
.AddOperation(realTest ? outPath.Balance.ReadMassOp(ref mass) : null)
|
|
.AddOperation(StateMachine.ControlBoard.UpdateTankWeightOp())
|
|
.AddOperation((StateMachine.Ambient != null)
|
|
? StateMachine.Ambient.ReadAmbientOp(airTemperature, airPressure, airHumidity)
|
|
: null)
|
|
.AddOperation(realTest ? (ticTac ? queryEnd1 : queryEnd2) : null)
|
|
.AddOperation(realTest ? processDataLoggingOp : null)
|
|
.EnterState();
|
|
do
|
|
{
|
|
e = StateMachine.WaitRunDevsRunOps();
|
|
if (e.Contains(Event.Error)) return Event.Error;
|
|
if (e.Contains(Event.UiCmdStop)) return Event.UiCmdStop;
|
|
if (e.Contains(Event.MeasurementCompleted)) return Event.MeasurementCompleted;
|
|
}
|
|
while ( (realTest && !e.Contains(Event.BalanceDone)) ||
|
|
!e.Contains(Event.ReadAllRegistersDone));
|
|
|
|
return Event.Done;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Prepares 'TestProgressEventArgs' object that update screens during the test
|
|
/// </summary>
|
|
/// <param name="test">Current 'Test' entity</param>
|
|
/// <param name="tstRslt">Current 'TestResult' entity</param>
|
|
/// <param name="cBrd">Control board component reference</param>
|
|
/// <param name="time">Current test time in [s]</param>
|
|
/// <param name="progress">Current progress 0 .. 1.0f</param>
|
|
/// <returns>Data for the UI</returns>
|
|
protected TestProgressEventArgs GetTestProgressData(Entities.Test test, Entities.TestResult tstRslt, bool testRunning, Elde.ControlBoardDev cBrd, float time, float progress)
|
|
{
|
|
TestProgressEventArgs data = new TestProgressEventArgs();
|
|
|
|
data.TestResult = tstRslt;
|
|
|
|
refFreq.Val = cBrd.ReferenceFreq;
|
|
data.FlowMtrFreq = refFreq;
|
|
|
|
data.Flow = refFlow;
|
|
data.Time = time;
|
|
data.StartMass = startMass;
|
|
data.Mass = mass;
|
|
|
|
data.Progress = progress;
|
|
float estCurrentTime = TimeEstimateBeginRpts + ((float)(tstRslt.RepetitionNr - 1) + progress) * TimeEstimateOneTest;
|
|
data.OveralProgress = estCurrentTime / TimeEstimateTotal;
|
|
|
|
data.Tin = tempIn;
|
|
data.Tout = tempOut;
|
|
data.Tdiv = tempDiv;
|
|
data.Pin = pressIn;
|
|
data.Pout = pressOut;
|
|
|
|
data.AmbientTemp = airTemperature;
|
|
data.AmbientPressure = airPressure;
|
|
data.AmbientHumidity = airHumidity;
|
|
|
|
if (testRunning)
|
|
{
|
|
/// Only when test is running
|
|
data.RefPulses = cBrd.EtPulses(0);
|
|
float refPulsesPerLtr = 1.0f / outPath.FlowMeter.LtrPerPulseCorrected(refFlow.Val); /// [pulse/ltr]
|
|
data.Volume = new FloatBox() { Name = "Volume", Format = "F1", Val = Formulas.VolumeFromPulses(data.RefPulses, refPulsesPerLtr) };
|
|
|
|
for (int i = 0; i < Program.WMsCount; i++)
|
|
{
|
|
if (sensPath.RegisterReaders[i] != null)
|
|
{
|
|
data.TestResult.Meters[i].PulsesMeter = WMPulses[i];
|
|
data.TestResult.Meters[i].PulsesMaster = WMRefPulses[i];
|
|
data.TestResult.Meters[i].VolumeMeter = Formulas.VolumeFromPulses(WMPulses[i], sensPath.RegisterReaders[i].PulsesPerLtr);
|
|
data.TestResult.Meters[i].VolumeRef = data.Volume.Val;
|
|
data.TestResult.Meters[i].VolumeErrorPct = Formulas.ErrorFromVolumes(data.TestResult.Meters[i].VolumeMeter, data.Volume.Val);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
data.Volume = new FloatBox() { Name = "Volume", Format = "F1", Val = 0 };
|
|
}
|
|
|
|
return data;
|
|
}
|
|
|
|
protected string TestResult2CsvLine(Entities.TestResult tstRslt)
|
|
{
|
|
System.Text.StringBuilder sb = new System.Text.StringBuilder();
|
|
|
|
sb.Append(tstRslt.TimeStart);
|
|
sb.Append(";"); sb.Append(tstRslt.BatchNr);
|
|
sb.Append(";"); sb.Append(tstRslt.TestName);
|
|
sb.Append(";"); sb.Append(tstRslt.RepetitionNr);
|
|
sb.Append(";"); sb.Append("1");
|
|
sb.Append(";"); sb.Append(tstRslt.Method);
|
|
sb.Append(";"); sb.Append(tstRslt.Volume);
|
|
sb.Append(";"); sb.Append(tstRslt.Qfrom);
|
|
sb.Append(";"); sb.Append(tstRslt.Qto);
|
|
sb.Append(";"); sb.Append(tstRslt.ErrLimLo);
|
|
sb.Append(";"); sb.Append(tstRslt.ErrLimHi);
|
|
sb.Append(";"); sb.Append("0");
|
|
sb.Append(";"); sb.Append("60");
|
|
sb.Append(";"); sb.Append("0");
|
|
sb.Append(";"); sb.Append("0");
|
|
sb.Append(";"); sb.Append("2");
|
|
sb.Append(";"); sb.Append(" ");
|
|
sb.Append(";"); sb.Append(outPath.Balance.Cfg.Name);
|
|
sb.Append(";"); sb.Append(tstRslt.AmbientTempAve);
|
|
sb.Append(";"); sb.Append(tstRslt.AmbientPressAve);
|
|
sb.Append(";"); sb.Append(tstRslt.AmbientHumiAve);
|
|
sb.Append(";"); sb.Append(tstRslt.PressInAvrg);
|
|
sb.Append(";"); sb.Append(tstRslt.PressOutAvrg);
|
|
sb.Append(";"); sb.Append(tstRslt.PressInStart);
|
|
sb.Append(";"); sb.Append(tstRslt.PressOutStart);
|
|
sb.Append(";"); sb.Append(tstRslt.PressInEnd);
|
|
sb.Append(";"); sb.Append(tstRslt.PressOutEnd);
|
|
sb.Append(";"); sb.Append(tstRslt.TempInAvrg);
|
|
sb.Append(";"); sb.Append(tstRslt.TempOutAvrg);
|
|
sb.Append(";"); sb.Append(tstRslt.TempDivAvrg);
|
|
sb.Append(";"); sb.Append(tstRslt.TempInStart);
|
|
sb.Append(";"); sb.Append(tstRslt.TempOutStart);
|
|
sb.Append(";"); sb.Append(tstRslt.TempDivStart);
|
|
sb.Append(";"); sb.Append(tstRslt.TempInEnd);
|
|
sb.Append(";"); sb.Append(tstRslt.TempOutEnd);
|
|
sb.Append(";"); sb.Append(tstRslt.TempDivEnd);
|
|
sb.Append(";"); sb.Append(tstRslt.MassStartRaw);
|
|
sb.Append(";"); sb.Append(tstRslt.MassStart);
|
|
sb.Append(";"); sb.Append(tstRslt.MassEndRaw);
|
|
sb.Append(";"); sb.Append(tstRslt.MassEnd);
|
|
sb.Append(";"); sb.Append(tstRslt.MassDiff);
|
|
sb.Append(";"); sb.Append(tstRslt.DensityDiv);
|
|
sb.Append(";"); sb.Append(tstRslt.DensityIn);
|
|
sb.Append(";"); sb.Append(tstRslt.DensityOut);
|
|
sb.Append(";"); sb.Append(" "); /// d_air: Hustota vzduchu: Sheet1 - K9
|
|
sb.Append(";"); sb.Append(" "); /// Buoyancy: Sheet1 - X9
|
|
sb.Append(";"); sb.Append(" "); /// Exp T: teraz vynechat
|
|
sb.Append(";"); sb.Append(" "); /// Exp P: teraz vynechat
|
|
sb.Append(";"); sb.Append(" "); /// pipe expansion: teraz vynechat
|
|
sb.Append(";"); sb.Append(tstRslt.FlowMass); /// Qm [kg/h]
|
|
sb.Append(";"); sb.Append(tstRslt.FlowVolume); /// Qv [l/h]
|
|
sb.Append(";"); sb.Append(tstRslt.VolumeCTV); /// Vet . . . komercne prava hodnota - podla vahy
|
|
sb.Append(";"); sb.Append(tstRslt.VolumeMaster); /// Velm . . . . objem podla etalonu
|
|
sb.Append(";"); sb.Append(" "); /// Vmass . . . objem podla druheho etalonu / prietokomeru pred tratou (teraz vynechavame)
|
|
sb.Append(";"); sb.Append(tstRslt.Time); /// t
|
|
sb.Append(";"); sb.Append(tstRslt.ErrorMaster); /// Eelm . . . chyba etalonu voci komercne pravej hodnote
|
|
sb.Append(";"); sb.Append(" "); /// Emass . . . chyba druheho etalonu voci komercne pravej hodnote (teraz vynechavame)
|
|
sb.Append(";"); sb.Append(1.0f / outPath.FlowMeter.LtrPerPulse);
|
|
/// Const.MID . konstanta eatlonu
|
|
sb.Append(";"); sb.Append(" "); /// Const.MA . . konstanta druheho etalonu
|
|
sb.Append(";"); sb.Append(tstRslt.TimeDivStart0); /// Time Div Start celkovy cas v [ms]
|
|
sb.Append(";"); sb.Append(tstRslt.TimeDivStart1); /// Time Div Start1
|
|
sb.Append(";"); sb.Append(tstRslt.TimeDivStart2); /// Time Div Start2
|
|
sb.Append(";"); sb.Append(tstRslt.TimeDivStart3); /// Time Div Start3
|
|
sb.Append(";"); sb.Append(tstRslt.TimeDivStart4); /// Time Div Start4
|
|
sb.Append(";"); sb.Append(tstRslt.TimeDivStart5); /// Time Div Start5
|
|
sb.Append(";"); sb.Append(tstRslt.TimeDivEnd0); /// Time Div End celkovy cas v [ms]
|
|
sb.Append(";"); sb.Append(tstRslt.TimeDivEnd1); /// Time Div End1
|
|
sb.Append(";"); sb.Append(tstRslt.TimeDivEnd2); /// Time Div End2
|
|
sb.Append(";"); sb.Append(tstRslt.TimeDivEnd3); /// Time Div End3
|
|
sb.Append(";"); sb.Append(tstRslt.TimeDivEnd4); /// Time Div End4
|
|
sb.Append(";"); sb.Append(tstRslt.TimeDivEnd5); /// Time Div End5
|
|
sb.Append(";"); sb.Append(tstRslt.PulsesMaster); /// Celkovy pocet et. pulzov skusky
|
|
sb.Append(";"); sb.Append(" "); /// - '' - pre druhy
|
|
for (int i = 0; i < tstRslt.Meters.Count; i++)
|
|
{
|
|
Entities.MeterTestResult mtrRslt = tstRslt.Meters[i];
|
|
|
|
sb.Append(";"); sb.Append(mtrRslt.SerialNr); /// WM Ser.No.
|
|
sb.Append(";"); sb.Append(mtrRslt.VolumeStart); /// WM Vinit - pri pevnom starte pociatocny stav natukany alebo cez inteligentny system
|
|
sb.Append(";"); sb.Append(mtrRslt.VolumeEnd); /// WM Vfin - pri pevnom starte konecny stav natukany alebo cez inteligentny system
|
|
sb.Append(";"); sb.Append(mtrRslt.VolumeMeter); /// WM Vmer - objem namerany vodomerom
|
|
sb.Append(";"); sb.Append(mtrRslt.VolumeRef); /// WM Vet - objem namerany stanicou
|
|
sb.Append(";"); sb.Append(mtrRslt.VolumeErrorPct); /// WM Emt - chyba vodomerom nameraneho objemu
|
|
sb.Append(";"); sb.Append(" "); /// WM U - neistota (zatial nechat prazdne)
|
|
sb.Append(";"); sb.Append(mtrRslt.PulsesMeter); /// WM Np met - pocet impulzov zo skusaneho meradla
|
|
sb.Append(";"); sb.Append(mtrRslt.PulsesMaster); /// WM Np elm - pocet impulzov etalonu pocas merania pre prislusny vodomer
|
|
sb.Append(";"); sb.Append(mtrRslt.Time); /// WM Tmet - cas merania (obmedzany pri synchro skuske)
|
|
bool ok = (mtrRslt.VolumeErrorPct >= tstRslt.ErrLimLo) && (mtrRslt.VolumeErrorPct <= tstRslt.ErrLimHi);
|
|
sb.Append(";"); sb.Append(ok ? "OK" : "NOK"); /// WM Vysledok (t.j. ci je v hraniciach chyb) - OK/NOK
|
|
sb.Append(";"); sb.Append(" "); /// WM AN value - hodnota z analogoveho prevodnika (teraz nic)
|
|
sb.Append(";"); sb.Append(" "); /// WM Vinit - pri datastreamovych hodnotach (alebo kamera)
|
|
sb.Append(";"); sb.Append(" "); /// WM Time init ???
|
|
sb.Append(";"); sb.Append(" "); /// WM Vend ???
|
|
sb.Append(";"); sb.Append(" "); /// WM Time end ???
|
|
}
|
|
for (int i = 0; i < tstRslt.CombinedMeters.Count; i++)
|
|
{
|
|
Entities.MeterTestResult mtrRslt = tstRslt.CombinedMeters[i];
|
|
|
|
sb.Append(";"); sb.Append(mtrRslt.SerialNr); /// WM Ser.No.
|
|
sb.Append(";"); sb.Append(mtrRslt.VolumeStart); /// WM Vinit - pri pevnom starte pociatocny stav natukany alebo cez inteligentny system
|
|
sb.Append(";"); sb.Append(mtrRslt.VolumeEnd); /// WM Vfin - pri pevnom starte konecny stav natukany alebo cez inteligentny system
|
|
sb.Append(";"); sb.Append(mtrRslt.VolumeMeter); /// WM Vmer - objem namerany vodomerom
|
|
sb.Append(";"); sb.Append(mtrRslt.VolumeRef); /// WM Vet - objem namerany stanicou
|
|
sb.Append(";"); sb.Append(mtrRslt.VolumeErrorPct); /// WM Emt - chyba vodomerom nameraneho objemu
|
|
sb.Append(";"); sb.Append(" "); /// WM U - neistota (zatial nechat prazdne)
|
|
sb.Append(";"); sb.Append(mtrRslt.PulsesMeter); /// WM Np met - pocet impulzov zo skusaneho meradla
|
|
sb.Append(";"); sb.Append(mtrRslt.PulsesMaster); /// WM Np elm - pocet impulzov etalonu pocas merania pre prislusny vodomer
|
|
sb.Append(";"); sb.Append(mtrRslt.Time); /// WM Tmet - cas merania (obmedzany pri synchro skuske)
|
|
bool ok = (mtrRslt.VolumeErrorPct >= tstRslt.ErrLimLo) && (mtrRslt.VolumeErrorPct <= tstRslt.ErrLimHi);
|
|
sb.Append(";"); sb.Append(ok ? "OK" : "NOK"); /// WM Vysledok (t.j. ci je v hraniciach chyb) - OK/NOK
|
|
sb.Append(";"); sb.Append(" "); /// WM AN value - hodnota z analogoveho prevodnika (teraz nic)
|
|
sb.Append(";"); sb.Append(" "); /// WM Vinit - pri datastreamovych hodnotach (alebo kamera)
|
|
sb.Append(";"); sb.Append(" "); /// WM Time init ???
|
|
sb.Append(";"); sb.Append(" "); /// WM Vend ???
|
|
sb.Append(";"); sb.Append(" "); /// WM Time end ???
|
|
}
|
|
sb.Append(";");
|
|
|
|
return sb.ToString();
|
|
}
|
|
}
|
|
}
|