- When STOP is pressed during PerformSteps() in the BeforeTest transition, Transition() returned immediately and skipped the common shutdown logic. This caused FM pumps and valves to remain in their previous state. - Perform the required safe shutdown (FM pump off and default valve setup) before returning UiCmdStop or Error.
2055 lines
104 KiB
C#
2055 lines
104 KiB
C#
///
|
|
/// Copyright (c) 2013-2021 Sensus Slovensko a.s.
|
|
///
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Threading;
|
|
using log4net;
|
|
using Common;
|
|
using Config.Entities;
|
|
using TBF.Rig.DataEntry;
|
|
using TBF.Rig.GenericDevices;
|
|
using TBF.Rig.Operations;
|
|
using TBF.Boxes;
|
|
using TBF.Resources;
|
|
using TBF.UiBridge;
|
|
|
|
namespace TBF.Rig.Sequences
|
|
{
|
|
/// <summary>
|
|
/// Sequence is a group of states that can be dynamically added to
|
|
/// and removed from the state machine
|
|
/// </summary>
|
|
public class SequenceBase : ProcessData
|
|
{
|
|
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");
|
|
|
|
|
|
public const int FlowSettingTimeoutSec = 300; /// Flow setting timeout = 5 min.
|
|
public const int StableMassMsrmntTimeoutSec = 300; /// Stable mass measurement timeout = 5 min.
|
|
|
|
|
|
///------------------------------------------------------------
|
|
/// Global static variables set only once.
|
|
///------------------------------------------------------------
|
|
public static IList<IFlowMeter> FlowMeters; /// list of reference flowmeters
|
|
public static IList<RegValvePosition> RegVPositions; /// 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
|
|
///------------------------------------------------------------
|
|
public static int ReferenceFlowmetersCount;
|
|
public static double[] CalibratedLtrPerRefPulse; /// Reference flowmeter coefficients
|
|
public static double Qrise;
|
|
public static double Qfall;
|
|
|
|
///------------------------------------------------------------
|
|
/// Test related (instance) variables.
|
|
/// Created when test sequence is open.
|
|
/// They persist during all repetitions of the same test
|
|
///------------------------------------------------------------
|
|
|
|
|
|
protected IOperation queryEnd1;
|
|
protected IOperation checkUiOp;
|
|
|
|
protected IOperation processDataLoggingOp;
|
|
protected IOperation enduranceDataLoggingOp;
|
|
|
|
|
|
protected GenericDevices.IDataEntry lastDataEntryCmpnt;
|
|
|
|
|
|
///TODO open valve
|
|
///
|
|
protected void OpenValveGrabImage(ControlBoard.IControlBoard cBrd,IOperation additionalOperation, IValve triggerValve,IList<Event> e, string stateName)
|
|
{
|
|
//Test if diverter is open
|
|
IDiverter diverter = cBrd.Devices.Diverter;
|
|
if (diverter != null)
|
|
{
|
|
log.DebugFormat("Diverter state - start Grab Image: {0}, number: {1}",
|
|
diverter.State == true ? "-to tank-" : "bypass tank", diverter.DiverterNr);
|
|
}
|
|
|
|
if (additionalOperation != null)
|
|
{
|
|
log.Debug("Open Valve GrabImage - with additionalOperation");
|
|
State valveOpen = State.Create(stateName)
|
|
.AddOperation(checkUiOp)
|
|
.AddOperation(cBrd.SetValvesOp(triggerValve, null))
|
|
.AddOperation(additionalOperation)
|
|
.EnterState();
|
|
}
|
|
else
|
|
{
|
|
log.Debug("Open Valve GrabImage - NO additionalOperation");
|
|
State valveOpen = State.Create(stateName)
|
|
.AddOperation(checkUiOp)
|
|
.AddOperation(cBrd.SetValvesOp(triggerValve, null))
|
|
.EnterState();
|
|
}
|
|
|
|
do
|
|
{
|
|
e = StateMachine.WaitRunDevsRunOps();
|
|
if (e.Contains(Event.Error)) break;
|
|
} while (e.Contains(Event.ValvesBusy));
|
|
log.Debug("Trigger send, opened valve: "+ triggerValve?.Name );
|
|
Thread.Sleep(1000);
|
|
|
|
if (diverter != null)
|
|
{
|
|
log.DebugFormat("Diverter state - after: {0}, diverter number: {1}",
|
|
diverter.State == true ? "-to tank-" : "bypass tank", diverter.DiverterNr);
|
|
}
|
|
}
|
|
|
|
protected void CloseValveGrabImage(ControlBoard.IControlBoard cBrd, IOperation additionalOperation, IValve triggerValve,IList<Event> e, string stateName)
|
|
{
|
|
//Test if diverter is open
|
|
IDiverter diverter = cBrd.Devices.Diverter;
|
|
if (diverter != null)
|
|
{
|
|
log.DebugFormat("Diverter state before Grab Image: {0}, number: {1}",
|
|
diverter.State == true ? "-to tank-" : "bypass tank", diverter.DiverterNr);
|
|
}
|
|
|
|
Thread.Sleep(2000);
|
|
if (additionalOperation != null)
|
|
{
|
|
log.Debug("Close Valve GrabImage - with additionalOperation");
|
|
State valveOpen = State.Create(stateName)
|
|
.AddOperation(checkUiOp)
|
|
.AddOperation(cBrd.SetValvesOp(null, triggerValve))
|
|
.AddOperation(additionalOperation)
|
|
.EnterState();
|
|
}
|
|
else
|
|
{
|
|
log.Debug("Close Valve GrabImage - NO additionalOperation");
|
|
State valveOpen = State.Create(stateName)
|
|
.AddOperation(checkUiOp)
|
|
.AddOperation(cBrd.SetValvesOp(null, triggerValve))
|
|
.EnterState();
|
|
}
|
|
|
|
do
|
|
{
|
|
e = StateMachine.WaitRunDevsRunOps();
|
|
if (e.Contains(Event.Error)) break;
|
|
} while (e.Contains(Event.ValvesBusy));
|
|
log.Debug("Trigger send, closed valve: "+ triggerValve?.Name );
|
|
|
|
if (diverter != null)
|
|
{
|
|
log.DebugFormat("Diverter state - after: {0}, num: {1}",
|
|
diverter.State == true ? "-to tank-" : "bypass tank", diverter.DiverterNr);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Used in tests in measurement loop to display remaining test time
|
|
/// </summary>
|
|
/// <param name="remainingTime">Remaining time in seconds</param>
|
|
protected void ShowRemainingTime(int remainingTime)
|
|
{
|
|
if (remainingTime > 60)
|
|
{
|
|
Bridge.OnActivity(this, string.Format("{0} ... {1} {2} {3} {4}", Strings.Test_in_progress, remainingTime / 60, "min", remainingTime % 60, Strings.sec));
|
|
}
|
|
else
|
|
{
|
|
Bridge.OnActivity(this, string.Format("{0} ... {1} s", Strings.Test_in_progress, remainingTime));
|
|
}
|
|
}
|
|
|
|
protected Event DrainTheTank(IScaleOrTank tank)
|
|
{
|
|
return DrainTheTank(tank, new List<IOperation>());
|
|
}
|
|
|
|
protected Event DrainTheTank(IScaleOrTank tank, IOperation extraOperation)
|
|
{
|
|
IList<IOperation> extraOperations = new List<IOperation>();
|
|
extraOperations.Add(extraOperation);
|
|
return DrainTheTank(tank, extraOperations);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Empties the tank: opens the emptying valve and measures the weight.
|
|
/// </summary>
|
|
/// <param name="drainValve">Valve to empty the tank</param>
|
|
/// <param name="tank">Scale underneath the tank</param>
|
|
/// <returns>Event.Done or Event.Error</returns>
|
|
protected Event DrainTheTank(IScaleOrTank tank, IList<IOperation> extraOperations)
|
|
{
|
|
IList<Event> e;
|
|
bool stopped = false;
|
|
Bridge.Bench2UI(ButtonsEtc.StopBtnEn);
|
|
IntBox remainingTimeSec = new IntBox();
|
|
|
|
Bridge.OnActivity(this, TBF.Resources.Strings.Emptying_tank);
|
|
|
|
if (tank.DrainValve2 == null)
|
|
{
|
|
///
|
|
/// Draining with 1 valve 'DrainValve'
|
|
///
|
|
State.Create("SequenceBase : Open the drain valve")
|
|
.AddOperation(checkUiOp)
|
|
.AddOperation(StateMachine.ControlBoardMain.SetValvesOp(tank.DrainValve, null))
|
|
.AddOperations(extraOperations)
|
|
.EnterState();
|
|
do
|
|
{
|
|
e = StateMachine.WaitRunDevsRunOps();
|
|
}
|
|
while (!e.Contains(Event.ValvesSet));
|
|
|
|
|
|
State.Create("SequenceBase : Draining the tank")
|
|
.AddOperation(checkUiOp)
|
|
.AddOperation(new TimerOp(tank.EmptyTimeSec, remainingTimeSec))
|
|
.AddOperations(extraOperations)
|
|
.EnterState();
|
|
do
|
|
{
|
|
e = StateMachine.WaitRunDevsRunOps();
|
|
if (e.Contains(Event.Error)) return Event.Error;
|
|
if (TestAndLogUiCmdStop(e))
|
|
{
|
|
stopped = true;
|
|
break;
|
|
}
|
|
///
|
|
if (!(tank is IScale))
|
|
{
|
|
Bridge.OnActivity(this, string.Format("{0} ... {1} {2} {3} {4}",
|
|
Strings.Emptying_tank,
|
|
remainingTimeSec.Val / 60, "min",
|
|
remainingTimeSec.Val % 60, Strings.sec));
|
|
}
|
|
}
|
|
while (!tank.IsEmpty() && !e.Contains(Event.TimerExpired));
|
|
}
|
|
else
|
|
{
|
|
///
|
|
/// Draining with 2 valves: 'DrainValve' is open in the 2nd half of time, 'DrainValve2' is open all the time
|
|
///
|
|
State.Create("SequenceBase : Open the drain valve")
|
|
.AddOperation(checkUiOp)
|
|
.AddOperation(StateMachine.ControlBoardMain.SetValvesOp(tank.DrainValve2, null))
|
|
.AddOperations(extraOperations)
|
|
.EnterState();
|
|
do
|
|
{
|
|
e = StateMachine.WaitRunDevsRunOps();
|
|
}
|
|
while (!e.Contains(Event.ValvesSet));
|
|
|
|
///
|
|
/// 1st half
|
|
///
|
|
State.Create("SequenceBase : Draining the tank")
|
|
.AddOperation(checkUiOp)
|
|
.AddOperation(new TimerOp(tank.EmptyTimeSec / 2, remainingTimeSec))
|
|
.AddOperations(extraOperations)
|
|
.EnterState();
|
|
do
|
|
{
|
|
e = StateMachine.WaitRunDevsRunOps();
|
|
if (e.Contains(Event.Error)) return Event.Error;
|
|
if (TestAndLogUiCmdStop(e))
|
|
{
|
|
stopped = true;
|
|
break;
|
|
}
|
|
///
|
|
if (!(tank is IScale))
|
|
{
|
|
Bridge.OnActivity(this, string.Format("{0} ... {1} {2} {3} {4}",
|
|
Strings.Emptying_tank,
|
|
(remainingTimeSec.Val + tank.EmptyTimeSec / 2) / 60, "min",
|
|
(remainingTimeSec.Val + tank.EmptyTimeSec / 2) % 60, Strings.sec));
|
|
}
|
|
}
|
|
while (!tank.IsEmpty() && !e.Contains(Event.TimerExpired));
|
|
|
|
///
|
|
/// 2nd half
|
|
///
|
|
if (!tank.IsEmpty())
|
|
{
|
|
State.Create("SequenceBase : Open the 2nd drain valve")
|
|
.AddOperation(checkUiOp)
|
|
.AddOperation(StateMachine.ControlBoardMain.SetValvesOp(tank.DrainValve, null))
|
|
.AddOperations(extraOperations)
|
|
.EnterState();
|
|
do
|
|
{
|
|
e = StateMachine.WaitRunDevsRunOps();
|
|
}
|
|
while (!e.Contains(Event.ValvesSet));
|
|
|
|
|
|
State.Create("SequenceBase : Draining the tank")
|
|
.AddOperation(checkUiOp)
|
|
.AddOperation(new TimerOp(tank.EmptyTimeSec / 2, remainingTimeSec))
|
|
.AddOperations(extraOperations)
|
|
.EnterState();
|
|
do
|
|
{
|
|
e = StateMachine.WaitRunDevsRunOps();
|
|
if (e.Contains(Event.Error)) return Event.Error;
|
|
if (TestAndLogUiCmdStop(e))
|
|
{
|
|
stopped = true;
|
|
break;
|
|
}
|
|
///
|
|
if (!(tank is IScale))
|
|
{
|
|
Bridge.OnActivity(this, string.Format("{0} ... {1} {2} {3} {4}",
|
|
Strings.Emptying_tank,
|
|
remainingTimeSec.Val / 60, "min",
|
|
remainingTimeSec.Val % 60, Strings.sec));
|
|
}
|
|
|
|
}
|
|
while (!tank.IsEmpty() && !e.Contains(Event.TimerExpired));
|
|
}
|
|
}
|
|
|
|
//
|
|
// Quit emptying, close the drain valve
|
|
//
|
|
State.Create("SequenceBase : Closing the drain valve")
|
|
.AddOperation(checkUiOp)
|
|
.AddOperation(StateMachine.ControlBoardMain.SetValvesOp(null, tank.DrainValve))
|
|
.AddOperations(extraOperations)
|
|
.EnterState();
|
|
do
|
|
{
|
|
e = StateMachine.WaitRunDevsRunOps();
|
|
if (e.Contains(Event.Error)) return Event.Error;
|
|
if (TestAndLogUiCmdStop(e)) return Event.UiCmdStop;
|
|
}
|
|
while (!e.Contains(Event.ValvesSet));
|
|
|
|
if (tank.DrainValve2 != null)
|
|
{
|
|
State.Create("SequenceBase : Closing the 2nd drain valve")
|
|
.AddOperation(checkUiOp)
|
|
.AddOperation(StateMachine.ControlBoardMain.SetValvesOp(null, tank.DrainValve2))
|
|
.AddOperations(extraOperations)
|
|
.EnterState();
|
|
do
|
|
{
|
|
e = StateMachine.WaitRunDevsRunOps();
|
|
if (e.Contains(Event.Error)) return Event.Error;
|
|
if (TestAndLogUiCmdStop(e)) return Event.UiCmdStop;
|
|
}
|
|
while (!e.Contains(Event.ValvesSet));
|
|
}
|
|
|
|
//if (tank is IScale)
|
|
//{
|
|
// State.Create("SequenceBase : Updating the mass")
|
|
// .AddOperation(checkUiOp)
|
|
// .AddOperation(new Operations.TimerOp(5))
|
|
// .AddOperations(extraOperations)
|
|
// .EnterState();
|
|
// do
|
|
// {
|
|
// e = StateMachine.WaitRunDevsRunOps();
|
|
// if (e.Contains(Event.Error)) return Event.Error;
|
|
// if (TestAndLogUiCmdStop(e)) return Event.UiCmdStop;
|
|
// }
|
|
// while (!e.Contains(Event.TimerExpired));
|
|
//}
|
|
|
|
if (stopped)
|
|
return Event.UiCmdStop;
|
|
else
|
|
return Event.Done;
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Passed as an argument to Transition(sequence, context)
|
|
/// </summary>
|
|
public enum TransitionContext
|
|
{
|
|
PurgeBegin,
|
|
BeforeTest, /// Before starting a test, paths are always applied aftr this sequence
|
|
BetweenTests, /// Between two repetitions of the same test
|
|
AfterTest, /// After completing a test
|
|
AfterTestWithOverlap, /// After completing transition sequence paths of the next test are selected and flow setting starts
|
|
PurgeEnd,
|
|
Stop,
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Calculates the estimate of transition sequence execution time
|
|
/// </summary>
|
|
/// <param name="transitionSequence">TransitionSequence entity</param>
|
|
/// <returns>Time in seconds</returns>
|
|
protected int GetTransitionTimeEst(TransitionSequence transitionSequence)
|
|
{
|
|
if (transitionSequence == null) return 1;
|
|
|
|
return 30; /// TODO: Implement time estimte calculation
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Returns a list of reg.valve positioning operations
|
|
/// </summary>
|
|
/// <param name="regVPositions">List of reg.valve/position pairs, position is in %, position LT 0 ... no operation</param>
|
|
/// <returns>List of reg.valve positioning operations</returns>
|
|
List<IOperation> GetRegVPositioningOps(IList<RegValvePosition> regVPositions)
|
|
{
|
|
List<IOperation> rvPosOps = new List<IOperation>();
|
|
|
|
if (regVPositions == null) return rvPosOps;
|
|
|
|
foreach (var rvp in regVPositions)
|
|
{
|
|
if (rvp.Position >= 0) /// Negative value means no position change
|
|
{
|
|
if (rvp.RegValve.IsCoax)
|
|
{
|
|
rvPosOps.Add(rvp.RegValve.SetRegValvePositionOp(rvp.Position, -1, 60));
|
|
}
|
|
else
|
|
{
|
|
rvPosOps.Add(rvp.RegValve.SetRegValvePositionOp(rvp.Position - 3.0, rvp.Position + 3.0, 60));
|
|
}
|
|
}
|
|
}
|
|
|
|
return rvPosOps;
|
|
}
|
|
|
|
|
|
/// <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 SetRegValvePositionOp)
|
|
/// </returns>
|
|
protected Event Transition(TransitionSequence transitionSequence, TransitionContext context)
|
|
{
|
|
bool stopFlag = false;
|
|
bool errorFlag = false;
|
|
IList<Event> e;
|
|
string message;
|
|
///
|
|
switch (context)
|
|
{
|
|
case TransitionContext.PurgeBegin: message = Strings.Purging_i_n; break;
|
|
case TransitionContext.BeforeTest: message = Strings.Test_start_sequence_i_n; break;
|
|
case TransitionContext.BetweenTests: message = Strings.Between_tests_sequence_i_n; break;
|
|
|
|
case TransitionContext.AfterTestWithOverlap:
|
|
case TransitionContext.AfterTest:
|
|
message = Strings.Test_stop_sequence_i_n;
|
|
break;
|
|
|
|
case TransitionContext.PurgeEnd: message = Strings.Emptying_i_n; break;
|
|
case TransitionContext.Stop: message = Strings.Test_stop_sequence_i_n; break;
|
|
default: message = "Transition"; break;
|
|
}
|
|
|
|
if (context == TransitionContext.PurgeBegin && FillState != FillState.Full) FillState = FillState.Unknown;
|
|
if (context == TransitionContext.PurgeEnd && FillState != FillState.Empty) FillState = FillState.Unknown;
|
|
|
|
if (transitionSequence == null)
|
|
{
|
|
///
|
|
/// No transition sequence defined --> Default action
|
|
///
|
|
if ((context == TransitionContext.AfterTest) || (context == TransitionContext.AfterTestWithOverlap))
|
|
{
|
|
log.WarnFormat("Transition(null, context={0}), turning FM pump off and setting valves to defaults", context);
|
|
|
|
if (inPath.Pump is GenericDevices.IPumpFM) (inPath.Pump as GenericDevices.IPumpFM).TurnOff();
|
|
|
|
State.Create("SequenceBase : Transition : TestEnd - Default action")
|
|
.AddOperation(checkUiOp)
|
|
.AddOperation(StateMachine.ControlBoardMain.SetValvesOp(StateMachine.DefaultValvesOpen, StateMachine.DefaultValvesClose))
|
|
.EnterState();
|
|
do {
|
|
e = StateMachine.WaitRunDevsRunOps();
|
|
if (TestAndLogUiCmdStop(e)) return Event.UiCmdStop;
|
|
}
|
|
while (!e.Contains(Event.ValvesSet));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
///
|
|
/// Fetch and execute the transition sequence, it is guaranteed (transitionSequence != null)
|
|
///
|
|
IList<TransitionStep> transitionSteps = new List<TransitionStep>();
|
|
if (StateMachine.TransitionSteps != null)
|
|
{
|
|
foreach (var step in StateMachine.TransitionSteps)
|
|
{
|
|
if ((step.TransitionSequence != null) && (step.TransitionSequence.Id == transitionSequence.Id))
|
|
{
|
|
transitionSteps.Add(step);
|
|
}
|
|
}
|
|
}
|
|
|
|
int stepsCount = transitionSteps.Count;
|
|
|
|
log.WarnFormat("Transition(sequence={0} ({1} steps), context={2})", transitionSequence.Name, stepsCount, context);
|
|
|
|
foreach (var step in transitionSteps)
|
|
{
|
|
//------------------------------------------------
|
|
string activity = string.Format(message, transitionSequence.Name, step.ItemNr + 1, stepsCount);
|
|
Bridge.OnActivity(this, activity);
|
|
Bridge.OnMessage(this, step.Message);
|
|
log.InfoFormat("{0} {1}", activity, step.Message);
|
|
//------------------------------------------------
|
|
|
|
/// Prepare operation to switch valves
|
|
IOperation setValvesOp = StateMachine.ControlBoardMain.SetValvesOp(Utils.ValvesOpen(step), Utils.ValvesClose(step));
|
|
|
|
/// Fetch the condition operation, null value is allowed if there is no condition
|
|
IOperation conditionOperation = null;
|
|
if (step.EndCondition != "None")
|
|
{
|
|
string[] fields = step.EndCondition.Split(new char[]{'~'});
|
|
if (fields.Length == 2)
|
|
{
|
|
ISequenceCondition seqCondition = TbfComponents.FindComponent(fields[0]) as ISequenceCondition;
|
|
int condID;
|
|
if ((seqCondition != null) && int.TryParse(fields[1], out condID))
|
|
{
|
|
conditionOperation = seqCondition.ConditionOp(condID);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// FM controlled pumps are canged imediately without using any state operations
|
|
log.DebugFormat("step.PumpWithFMPcts = {0}", step.PumpWithFMPcts);
|
|
float[] allFMPumpPcts = Utils.GetPumpWithFMPcts(step.PumpWithFMPcts);
|
|
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();
|
|
}
|
|
}
|
|
|
|
|
|
Utils.UpdateRegVPositionsFromStr(ref RegVPositions, step.RegulValvesPct);
|
|
IList<IOperation> rvPosOps = GetRegVPositioningOps(RegVPositions);
|
|
|
|
/// Max. one SetRegValvePositionOp can be started or stopped in one sub-step.
|
|
/// Therefore SetRegValvePositionOp operations are added and removed to subsequent states one by one.
|
|
int delay = Math.Max(2, step.Duration - rvPosOps.Count + 2);
|
|
|
|
///
|
|
int lastStartedRV = -1;
|
|
for (int i = 0; i < rvPosOps.Count; i++)
|
|
{
|
|
log.DebugFormat("SequenceBase.Transition() : Step {0} start, opening={1}, closing={2}", step.ItemNr + 1, step.ValvesOpen, step.ValvesClose);
|
|
State stepStrt = State
|
|
.Create(string.Format("SequenceBase.Transition() : Step {0} start, opening={1}, closing={2}", step.ItemNr + 1, step.ValvesOpen, step.ValvesClose))
|
|
.AddOperation(checkUiOp)
|
|
.AddOperation(conditionOperation)
|
|
.AddOperation(setValvesOp);
|
|
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 (TestAndLogUiCmdStop(e)) { stopFlag = true; break; }
|
|
}
|
|
/// Max. valaue of lastStartedRV after exitting the loop is (rvPosOps.Count - 1)
|
|
|
|
if (!stopFlag && !errorFlag)
|
|
{
|
|
log.DebugFormat("SequenceBase.Transition() : Step {0} delay {1}s, opening={2}, closing={3}", step.ItemNr + 1, delay, step.ValvesOpen, step.ValvesClose);
|
|
State stepDelay = State
|
|
.Create(string.Format("SequenceBase.Transition() : Step {0} delay {1}s, opening={2}, closing={3}", step.ItemNr + 1, delay, step.ValvesOpen, step.ValvesClose))
|
|
.AddOperation(checkUiOp)
|
|
.AddOperation(conditionOperation)
|
|
.AddOperation(setValvesOp)
|
|
.AddOperation(new TimerOp(delay));
|
|
for (int j = 0; j <= lastStartedRV; j++)
|
|
{
|
|
stepDelay.AddOperation(rvPosOps[j]);
|
|
}
|
|
stepDelay.EnterState();
|
|
bool endContitionFulfilled = false;
|
|
do
|
|
{
|
|
e = StateMachine.WaitRunDevsRunOps();
|
|
if (e.Contains(Event.Error) || e.Contains(Event.RegulValveTimeOut)) { errorFlag = true; break; }
|
|
if (TestAndLogUiCmdStop(e)) { stopFlag = true; break; }
|
|
|
|
if (e.Contains(Event.ConditionMet)) endContitionFulfilled = true; ;
|
|
/*
|
|
switch (step.EndCondition)
|
|
{
|
|
case StepCondition.Scale1Empty:
|
|
endContitionFulfilled = (StateMachine.Scale1 == null) || StateMachine.Scale1.IsEmpty();
|
|
break;
|
|
case StepCondition.Scale2Empty:
|
|
endContitionFulfilled = (StateMachine.Scale2 == null) || StateMachine.Scale2.IsEmpty();
|
|
break;
|
|
case StepCondition.Scale3Empty:
|
|
endContitionFulfilled = (StateMachine.Scale3 == null) || StateMachine.Scale3.IsEmpty();
|
|
break;
|
|
case StepCondition.AllScalesEmpty:
|
|
endContitionFulfilled = ((StateMachine.Scale1 == null) || StateMachine.Scale1.IsEmpty()) &&
|
|
((StateMachine.Scale2 == null) || StateMachine.Scale2.IsEmpty()) &&
|
|
((StateMachine.Scale3 == null) || StateMachine.Scale3.IsEmpty());
|
|
break;
|
|
}
|
|
*/
|
|
}
|
|
while (e.Contains(Event.ValvesBusy) || (!endContitionFulfilled && e.Contains(Event.TimerBusy) && !e.Contains(Event.Next)));
|
|
}
|
|
|
|
for (int first = 1; first <= lastStartedRV; first++)
|
|
{
|
|
log.DebugFormat("SequenceBase.Transition() : Step {0} stop, opening={1}, closing={2}", step.ItemNr + 1, step.ValvesOpen, step.ValvesClose);
|
|
State stepStop = State
|
|
.Create(string.Format("SequenceBase.Transition() : Step {0} stop, opening={1}, closing={2}", step.ItemNr + 1, step.ValvesOpen, step.ValvesClose))
|
|
.AddOperation(checkUiOp)
|
|
.AddOperation(conditionOperation)
|
|
.AddOperation(setValvesOp);
|
|
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 (TestAndLogUiCmdStop(e)) { stopFlag = true; }
|
|
}
|
|
|
|
if (errorFlag || stopFlag) break;
|
|
}
|
|
|
|
Bridge.OnMessage(this, string.Empty); /// Clear the last step message
|
|
}
|
|
|
|
///
|
|
/// Do this after executing the transition sequence
|
|
///
|
|
if (context == TransitionContext.Stop || errorFlag || stopFlag)
|
|
{
|
|
log.ErrorFormat("Transition({0}, context={1}) errorFlag={2} stopFlag={3} ... stoppng all pumps off",
|
|
(transitionSequence != null) ? transitionSequence.Name : "null", context, errorFlag, stopFlag);
|
|
|
|
///
|
|
/// On error or when STOP pressed
|
|
///
|
|
foreach (var fmPump in PumpsWithFM) fmPump.TurnOff();
|
|
log.Debug("STOP or ERROR: Pumps with FM stopped!");
|
|
|
|
if (inPath != null)
|
|
{
|
|
///
|
|
/// Stop the pump
|
|
///
|
|
State.Create("SequenceBase.Transition() : Test stopped -> Stopping the pump")
|
|
.AddOperation(checkUiOp)
|
|
.AddOperation(StateMachine.ControlBoardMain.SetValvesOp(null, inPath.Pump))
|
|
.EnterState();
|
|
do {
|
|
e = StateMachine.WaitRunDevsRunOps();
|
|
if (e.Contains(Event.Error)) return Event.Error;
|
|
}
|
|
while (!e.Contains(Event.ValvesSet));
|
|
}
|
|
}
|
|
else if (context == TransitionContext.BeforeTest && inPath != null && benchPath != null && outPath != null)
|
|
{
|
|
log.WarnFormat("Transition(any, context={0}), setting the required route before a test", context);
|
|
|
|
///
|
|
/// Always set route at the beginning of this test
|
|
///
|
|
List<IOperation> regVPosOps = GetRegVPositioningOps(inPath.RegVPositions);
|
|
regVPosOps.AddRange(GetRegVPositioningOps(outPath.RegVPositions));
|
|
Event evnt = PerformSteps(BuiltIn.ValveBase.Merge(inPath.ValvesOpen, benchPath.ValvesOpen, outPath.ValvesOpen),
|
|
BuiltIn.ValveBase.Merge(inPath.ValvesClose, benchPath.ValvesClose, outPath.ValvesClose),
|
|
regVPosOps,
|
|
"SequenceBase : Transition : TestStart - Default action");
|
|
|
|
///
|
|
/// Bugfix: PerformSteps() may return Error or UiCmdStop before the common
|
|
/// transition shutdown code is reached.
|
|
///
|
|
if (evnt == Event.Error || evnt == Event.UiCmdStop)
|
|
{
|
|
log.WarnFormat(
|
|
"Transition(context={0}): PerformSteps returned {1}, performing safe shutdown (FM pump off, default valves).",
|
|
context,
|
|
evnt);
|
|
|
|
if (inPath.Pump is GenericDevices.IPumpFM)
|
|
(inPath.Pump as GenericDevices.IPumpFM).TurnOff();
|
|
|
|
State.Create("SequenceBase : Transition : STOP/ERROR - Setting default valves")
|
|
.AddOperation(checkUiOp)
|
|
.AddOperation(StateMachine.ControlBoardMain.SetValvesOp(
|
|
StateMachine.DefaultValvesOpen,
|
|
StateMachine.DefaultValvesClose))
|
|
.EnterState();
|
|
|
|
do
|
|
{
|
|
e = StateMachine.WaitRunDevsRunOps();
|
|
if (TestAndLogUiCmdStop(e)) return Event.UiCmdStop;
|
|
}
|
|
while (!e.Contains(Event.ValvesSet));
|
|
|
|
return evnt;
|
|
}
|
|
}
|
|
else if (context == TransitionContext.AfterTestWithOverlap && nextInPath != null && nextBenchPath != null && nextOutPath != null)
|
|
{
|
|
log.WarnFormat("Transition(., context={0}), overlapped action (next flow regulation)", context);
|
|
|
|
///
|
|
/// Set route for the next test
|
|
///
|
|
List<IOperation> regVPosOps = GetRegVPositioningOps(nextInPath.RegVPositions);
|
|
regVPosOps.AddRange(GetRegVPositioningOps(nextOutPath.RegVPositions));
|
|
Event evnt = PerformSteps(BuiltIn.ValveBase.Merge(nextInPath.ValvesOpen, nextBenchPath.ValvesOpen, nextOutPath.ValvesOpen),
|
|
BuiltIn.ValveBase.Merge(nextInPath.ValvesClose, nextBenchPath.ValvesClose, nextOutPath.ValvesClose),
|
|
regVPosOps,
|
|
"SequenceBase : AfterTestWithOverlap : Default action");
|
|
|
|
if (evnt == Event.Error || evnt == Event.UiCmdStop) return evnt;
|
|
|
|
/// Set PID coefficient, etc.
|
|
if (StateMachine.ControlBoardMain is ControlBoard.Uni.UniCB)
|
|
{
|
|
int[] filters = new int[] { 0, 0, 0, 0, 0, 0, 0, 0 };
|
|
(StateMachine.ControlBoardMain as ControlBoard.Uni.UniCB).SetFiltersPidShortPulses(filters, nextPidCoef, (nextShortPulses == 0) ? 0 : 1);
|
|
}
|
|
|
|
/// Set pump power
|
|
if (nextInPath.Pump is GenericDevices.IPumpFM) (nextInPath.Pump as GenericDevices.IPumpFM).TurnOn(nextPumpPower);
|
|
|
|
//------------------------------------------------
|
|
Bridge.OnActivity(this, Strings.Setting_the_flow);
|
|
//------------------------------------------------
|
|
/// Set flow for the next test
|
|
State.Create(string.Format("SequenceBase : AfterTestWithOverlap - Setting the flow to {0} - {1} m3/h", nextQfrom, nextQto))
|
|
.AddOperation(checkUiOp)
|
|
.AddOperation(nextOutPath.RegValve.SetFlowAndMeasureOp(nextOutPath.FlowMeter, nextQfrom, nextQto, RefFlow, FlowSettingTimeoutSec, 0))
|
|
.EnterState();
|
|
do {
|
|
e = StateMachine.WaitRunDevsRunOps();
|
|
|
|
if (e.Contains(Event.OpArgumentError)) return Event.Error;
|
|
if (TestAndLogUiCmdStop(e)) return Event.UiCmdStop;
|
|
if (e.Contains(Event.RegulValveTimeOut))
|
|
{
|
|
Bridge.OnError(this, Strings.Flow_adjustment_failed);
|
|
return Event.UiCmdStop;
|
|
}
|
|
}
|
|
while (!e.Contains(Event.Busy) && !e.Contains(Event.FlowReached));
|
|
}
|
|
|
|
if (errorFlag)
|
|
return Event.Error;
|
|
else if (stopFlag)
|
|
return Event.UiCmdStop;
|
|
else
|
|
{
|
|
if (context == TransitionContext.PurgeBegin) FillState = FillState.Full;
|
|
if (context == TransitionContext.PurgeEnd) FillState = FillState.Empty;
|
|
return Event.Done;
|
|
}
|
|
}
|
|
|
|
|
|
Event PerformSteps(IList<IValve> valvesToOpen, IList<IValve> valvesToClose, IList<IOperation> rvPosOps, string stateTitle)
|
|
{
|
|
bool stopFlag = false;
|
|
bool errorFlag = false;
|
|
IList<Event> e;
|
|
|
|
IOperation setValvesOp = StateMachine.ControlBoardMain.SetValvesOp(valvesToOpen, valvesToClose);
|
|
|
|
int lastStartedRV = -1;
|
|
for (int i = 0; i < rvPosOps.Count; i++)
|
|
{
|
|
State stepStrt = State.Create(stateTitle)
|
|
.AddOperation(checkUiOp)
|
|
.AddOperation(setValvesOp);
|
|
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 (TestAndLogUiCmdStop(e)) { stopFlag = true; break; }
|
|
}
|
|
/// Max. valaue of lastStartedRV after exitting the loop is (rvPosOps.Count - 1)
|
|
|
|
|
|
if (!stopFlag && !errorFlag)
|
|
{
|
|
State stepRegul = State.Create(stateTitle)
|
|
.AddOperation(checkUiOp)
|
|
.AddOperation(setValvesOp);
|
|
for (int j = 0; j <= lastStartedRV; j++) stepRegul.AddOperation(rvPosOps[j]);
|
|
stepRegul.EnterState();
|
|
|
|
do {
|
|
e = StateMachine.WaitRunDevsRunOps();
|
|
if (e.Contains(Event.Error) || e.Contains(Event.RegulValveTimeOut)) { errorFlag = true; break; }
|
|
if (TestAndLogUiCmdStop(e)) { stopFlag = true; break; }
|
|
}
|
|
while (e.Contains(Event.ValvesBusy) && !e.Contains(Event.Next));
|
|
}
|
|
|
|
|
|
for (int first = 1; first <= lastStartedRV; first++)
|
|
{
|
|
State stepStop = State.Create(stateTitle)
|
|
.AddOperation(checkUiOp)
|
|
.AddOperation(setValvesOp);
|
|
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 (TestAndLogUiCmdStop(e)) { stopFlag = true; }
|
|
}
|
|
|
|
if (stopFlag) return Event.UiCmdStop;
|
|
if (errorFlag) return Event.Error;
|
|
return Event.Done;
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Opens a modeless dialog for entering data at the beginning of a procedure (serial numbers)
|
|
/// </summary>
|
|
/// <returns>true = OK, false = stop pressed</returns>
|
|
protected bool OpenCycleBeginForm(IRegReader[] regReadersOptional = null)
|
|
{
|
|
lastDataEntryCmpnt = TbfComponents.FindComponent(StateMachine.Procedure.DataEntry) as GenericDevices.IDataEntry;
|
|
|
|
if (lastDataEntryCmpnt is IHasCycleBeginForm)
|
|
{
|
|
Bridge.OnActivity(this, Strings.Enter_water_meter_data);
|
|
State.Create("MainSeq : Enter begin data")
|
|
.AddPermanentOperation((lastDataEntryCmpnt as IHasCycleBeginForm).ShowCycleBeginFormOp( regReadersOptional))
|
|
.AddOperation(checkUiOp)
|
|
.EnterState();
|
|
|
|
if (TestAndLogUiCmdStop(StateMachine.WaitRunDevsRunOps())) return false; /// Return false when STOP pressed
|
|
}
|
|
|
|
return true; /// OK (=either a cycle beginning form is open or DataEntry component is not IHasCycleBeginForm)
|
|
}
|
|
|
|
|
|
/// <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 UIFlowControl WaitBeginFormClosed()
|
|
{
|
|
GenericDevices.IDataEntry dataEntryCmpnt =
|
|
TbfComponents.FindComponent(StateMachine.Procedure.DataEntry) as GenericDevices.IDataEntry;
|
|
|
|
bool stopPressed = false; /// true when STOP button pressed
|
|
|
|
if (dataEntryCmpnt is IHasCycleBeginForm)
|
|
{
|
|
IList<Event> e;
|
|
|
|
///
|
|
/// Wait until modeless form is closed by the user if it is stil open
|
|
///
|
|
if ( State.LastEvents.Contains(Event.ModelessFormIsOpen))
|
|
{
|
|
State.Create("MainSeq : Wait until the entry form is closed")
|
|
.AddOperation(checkUiOp)
|
|
.EnterState();
|
|
do
|
|
{
|
|
e = StateMachine.WaitRunDevsRunOps();
|
|
if (TestAndLogUiCmdStop(e))
|
|
{
|
|
stopPressed = true;
|
|
break;
|
|
}
|
|
}
|
|
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 : Stopping modeless form")
|
|
.AddOperation(checkUiOp)
|
|
.RemovePermanentOperation(dataEntryCmpnt as IOperation)
|
|
.EnterState();
|
|
e = StateMachine.WaitRunDevsRunOps();
|
|
|
|
if (TestAndLogUiCmdStop(e)) { stopPressed = true; }
|
|
}
|
|
|
|
return stopPressed ? UIFlowControl.Stop : UIFlowControl.Continue;
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Forces closing of a modeless dialog for entering data at the beginnig of a procedure.
|
|
/// This function is typically called before starting a new cycle
|
|
/// in case previous cycle was aborted.
|
|
/// </summary>
|
|
protected void CloseBeginForm()
|
|
{
|
|
if (StateMachine.Procedure == null || StateMachine.Procedure.DataEntry == null) return;
|
|
|
|
GenericDevices.IDataEntry dataEntryCmpnt =
|
|
TbfComponents.FindComponent(StateMachine.Procedure.DataEntry) as GenericDevices.IDataEntry;
|
|
|
|
if ((dataEntryCmpnt is IHasCycleBeginForm) &&
|
|
(State.LastEvents.Contains(Event.ModelessFormIsOpen) || State.LastEvents.Contains(Event.ModelessFormClosed)))
|
|
{
|
|
IList<Event> e;
|
|
|
|
/// 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 : Stopping modeless form")
|
|
.RemovePermanentOperation(dataEntryCmpnt as IOperation)
|
|
.EnterState();
|
|
do
|
|
{
|
|
e = StateMachine.WaitRunDevsRunOps();
|
|
}
|
|
while (e.Contains(Event.ModelessFormIsOpen));
|
|
}
|
|
}
|
|
|
|
|
|
protected Event SetFlowEtc(Test test, IFlowMeter flowMeter, IRegValve regulValve, IValve pump, IValve stopBFValve, IList<IOperation> extraOperations, bool doNotWait)
|
|
{
|
|
IList<Event> e;
|
|
Event retVal = Event.Done;
|
|
|
|
if (pump is GenericDevices.IPumpFM) (pump as GenericDevices.IPumpFM).TurnOn(test.PumpPower);
|
|
///
|
|
State.Create(string.Format("{0}({1}) : Starting the pump", test.Method, test.Name))
|
|
.AddOperation(checkUiOp)
|
|
.AddOperations(extraOperations)
|
|
.AddOperation(pump != null ? StateMachine.ControlBoardMain.SetValvesOp(pump, null) : null)
|
|
.EnterState();
|
|
do
|
|
{
|
|
e = StateMachine.WaitRunDevsRunOps();
|
|
//Bridge.OnProcessData(this, new ProcessDataEventArgs(test, repetitionNr, Progress.FlowSetting));
|
|
//Bridge.OnTestProgress(this, new TestProgressEventArgs(test, repetitionNr, Progress.FlowSetting));
|
|
|
|
if (TestAndLogUiCmdStop(e)) return Event.UiCmdStop;
|
|
if (e.Contains(Event.Error)) return Event.Error;
|
|
}
|
|
while (e.Contains(Event.ValvesBusy) /* || !e.Contains(Event.AllPositionsReached)*/);
|
|
|
|
|
|
if (test.TimePump2StartV > 0)
|
|
{
|
|
State.Create(string.Format("{0}({1}) : Waiting after the pump started", test.Method, test.Name))
|
|
.AddOperation(checkUiOp)
|
|
.AddOperation(new Operations.TimerOp(test.TimePump2StartV))
|
|
.AddOperations(extraOperations)
|
|
.EnterState();
|
|
do
|
|
{
|
|
e = StateMachine.WaitRunDevsRunOps();
|
|
//Bridge.OnProcessData(this, new ProcessDataEventArgs(test, repetitionNr, Progress.FlowSetting));
|
|
//Bridge.OnTestProgress(this, new TestProgressEventArgs(test, repetitionNr, Progress.FlowSetting));
|
|
|
|
if (TestAndLogUiCmdStop(e)) return Event.UiCmdStop;
|
|
}
|
|
while (!e.Contains(Event.TimerExpired));
|
|
}
|
|
|
|
|
|
if (stopBFValve != null)
|
|
{
|
|
State.Create(string.Format("{0}({1}) : Opening the stop backflow valve", test.Method, test.Name))
|
|
.AddOperation(checkUiOp)
|
|
.AddOperation(StateMachine.ControlBoardMain.SetValvesOp(stopBFValve, null))
|
|
.AddOperations(extraOperations)
|
|
.EnterState();
|
|
do
|
|
{
|
|
e = StateMachine.WaitRunDevsRunOps();
|
|
if (TestAndLogUiCmdStop(e)) return Event.UiCmdStop;
|
|
if (e.Contains(Event.Error)) return Event.Error;
|
|
}
|
|
while (!e.Contains(Event.ValvesSet));
|
|
}
|
|
|
|
|
|
if (test.TimeBeforeFlow > 0)
|
|
{
|
|
State.Create(string.Format("{0}({1}) : Waiting before flow setting process starts", test.Method, test.Name))
|
|
.AddOperation(checkUiOp)
|
|
.AddOperation(new Operations.TimerOp(test.TimeBeforeFlow))
|
|
.AddOperations(extraOperations)
|
|
.EnterState();
|
|
do
|
|
{
|
|
e = StateMachine.WaitRunDevsRunOps();
|
|
//Bridge.OnProcessData(this, new ProcessDataEventArgs(test, repetitionNr, Progress.FlowSetting));
|
|
//Bridge.OnTestProgress(this, new TestProgressEventArgs(test, repetitionNr, Progress.FlowSetting));
|
|
|
|
if (TestAndLogUiCmdStop(e)) return Event.UiCmdStop;
|
|
}
|
|
while (!e.Contains(Event.TimerExpired));
|
|
}
|
|
|
|
//------------------------------------------------
|
|
Bridge.OnActivity(this, Strings.Setting_the_flow);
|
|
//------------------------------------------------
|
|
State.Create(string.Format("{0}({1}) : Setting the flow", test.Method, test.Name))
|
|
.AddOperation(checkUiOp)
|
|
.AddOperation(doNotWait ? regulValve.SetFlowAndMeasureOp(flowMeter, test.QfromM3ph(), test.QtoM3ph(), RefFlow, FlowSettingTimeoutSec, 0)
|
|
: StateMachine.ControlBoardMain.SetFlowOp(test.QfromM3ph(), test.QtoM3ph(), RefFlow, FlowSettingTimeoutSec))
|
|
.AddOperations(extraOperations)
|
|
.EnterState();
|
|
do
|
|
{
|
|
e = StateMachine.WaitRunDevsRunOps();
|
|
//Bridge.OnProcessData(this, new ProcessDataEventArgs(test, repetitionNr, Progress.FlowSetting));
|
|
//Bridge.OnTestProgress(this, new TestProgressEventArgs(test, repetitionNr, Progress.FlowSetting));
|
|
|
|
if (e.Contains(Event.OpArgumentError)) return Event.OpArgumentError;
|
|
if (TestAndLogUiCmdStop(e)) return Event.UiCmdStop;
|
|
if (e.Contains(Event.RegulValveTimeOut))
|
|
{
|
|
Bridge.OnError(this, Strings.Flow_adjustment_failed);
|
|
return Event.RecoverableError;
|
|
}
|
|
if (e.Contains(Event.Next)) return Event.Done;
|
|
}
|
|
while (!(e.Contains(Event.FlowReached) || (doNotWait && e.Contains(Event.Busy)))); /// Stay in the loop while e.Contains(Event.Starting)
|
|
|
|
return retVal;
|
|
}
|
|
|
|
|
|
/// <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;
|
|
|
|
State.Create("Read water meters")
|
|
.AddOperation(checkUiOp)
|
|
.AddOperations(measureOperations)
|
|
.AddOperation(benchPath.TempMtrUp == null ? null : benchPath.TempMtrUp.ReadTempOp(ref TempUp))
|
|
.AddOperation(benchPath.TempMtrDown == null ? null : benchPath.TempMtrDown.ReadTempOp(ref TempDown))
|
|
.AddOperation(outPath.TempMtrDiv == null ? null : outPath.TempMtrDiv.ReadTempOp(ref TempDiv))
|
|
.AddOperation(benchPath.PressMtrUp == null ? null : benchPath.PressMtrUp.ReadPressureOp(ref PressUp))
|
|
.AddOperation(benchPath.PressMtrDown == null ? null : benchPath.PressMtrDown.ReadPressureOp(ref PressDown))
|
|
.AddOperation(benchPath.PressMtrDelta == null ? null : benchPath.PressMtrDelta.ReadPressureOp(ref PressDelta))
|
|
.AddOperation(benchPath.ElectricMtrUp == null ? null : benchPath.ElectricMtrUp.ReadAdjustableOp(ref ElectricUp))
|
|
.AddOperation(benchPath.ElectricMtrDown == null ? null : benchPath.ElectricMtrDown.ReadAdjustableOp(ref ElectricDown))
|
|
.AddOperation(benchPath.ElectricMtrDelta == null ? null : benchPath.ElectricMtrDelta.ReadAdjustableOp(ref ElectricDelta))
|
|
.AddOperation(heatMetersPath == null ? null : heatMetersPath.TMeterRefWarm1.ReadTempOp(ref TempRefHi1))
|
|
.AddOperation(heatMetersPath == null ? null : heatMetersPath.TMeterRefWarm2.ReadTempOp(ref TempRefHi2))
|
|
.AddOperation(heatMetersPath == null ? null : heatMetersPath.TMeterRefCold1.ReadTempOp(ref TempRefLo1))
|
|
.AddOperation(heatMetersPath == null ? null : heatMetersPath.TMeterRefCold2.ReadTempOp(ref TempRefLo2))
|
|
.AddOperation(realTest ? queryEnd1 : null)
|
|
.AddOperation(realTest ? processDataLoggingOp : null)
|
|
.EnterState();
|
|
{
|
|
/// Invoke Run() of all operatios once
|
|
e = StateMachine.WaitRunDevsRunOps();
|
|
if (e.Contains(Event.Error)) return Event.Error;
|
|
if (TestAndLogUiCmdStop(e)) return Event.UiCmdStop;
|
|
if (e.Contains(Event.TestCompleted) || e.Contains(Event.Next)) return Event.TestCompleted;
|
|
}
|
|
|
|
return Event.Done;
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Update temperature, pressure, water density and ambient values
|
|
/// including their statistics in the test results structure.
|
|
/// </summary>
|
|
/// <param name="tstRslt">Test results</param>
|
|
protected void UpdateTempPressDensAmb(Results.Entities.TestRslt tstRslt)
|
|
{
|
|
tstRslt.AmbTempMean = (float)AmbTempStat.Average;
|
|
tstRslt.AmbTempStart = (float)AmbTempStat.First;
|
|
tstRslt.AmbTempEnd = (float)AmbTempStat.Last;
|
|
tstRslt.AmbTempMin = (float)AmbTempStat.Min;
|
|
tstRslt.AmbTempMax = (float)AmbTempStat.Max;
|
|
tstRslt.AmbPressMean = (float)AmbPressStat.Average;
|
|
tstRslt.AmbPressStart = (float)AmbPressStat.First;
|
|
tstRslt.AmbPressEnd = (float)AmbPressStat.Last;
|
|
tstRslt.AmbPressMin = (float)AmbPressStat.Min;
|
|
tstRslt.AmbPressMax = (float)AmbPressStat.Max;
|
|
tstRslt.AmbHumiMean = (float)AmbHumiStat.Average;
|
|
tstRslt.AmbHumiStart = (float)AmbHumiStat.First;
|
|
tstRslt.AmbHumiEnd = (float)AmbHumiStat.Last;
|
|
tstRslt.AmbHumiMin = (float)AmbHumiStat.Min;
|
|
tstRslt.AmbHumiMax = (float)AmbHumiStat.Max;
|
|
tstRslt.PressUpMean = (float)PressUpStat.Average;
|
|
tstRslt.PressUpStart = (float)PressUpStat.First;
|
|
tstRslt.PressUpEnd = (float)PressUpStat.Last;
|
|
tstRslt.PressUpMin = (float)PressUpStat.Min;
|
|
tstRslt.PressUpMax = (float)PressUpStat.Max;
|
|
tstRslt.PressDownMean = (float)PressDownStat.Average;
|
|
tstRslt.PressDownStart = (float)PressDownStat.First;
|
|
tstRslt.PressDownEnd = (float)PressDownStat.Last;
|
|
tstRslt.PressDownMin = (float)PressDownStat.Min;
|
|
tstRslt.PressDownMax = (float)PressDownStat.Max;
|
|
tstRslt.PressDeltaMean = (float)PressDeltaStat.Average;
|
|
tstRslt.PressDeltaStart = (float)PressDeltaStat.First;
|
|
tstRslt.PressDeltaEnd = (float)PressDeltaStat.Last;
|
|
tstRslt.PressDeltaMin = (float)PressDeltaStat.Min;
|
|
tstRslt.PressDeltaMax = (float)PressDeltaStat.Max;
|
|
tstRslt.ConductMean = (float)ConductStat.Average;
|
|
tstRslt.ConductStart = (float)ConductStat.First;
|
|
tstRslt.ConductEnd = (float)ConductStat.Last;
|
|
tstRslt.ConductMin = (float)ConductStat.Min;
|
|
tstRslt.ConductMax = (float)ConductStat.Max;
|
|
tstRslt.TempUpMean = (float)TempUpStat.Average;
|
|
tstRslt.TempUpStart = (float)TempUpStat.First;
|
|
tstRslt.TempUpEnd = (float)TempUpStat.Last;
|
|
tstRslt.TempUpMin = (float)TempUpStat.Min;
|
|
tstRslt.TempUpMax = (float)TempUpStat.Max;
|
|
tstRslt.TempDownMean = (float)TempDownStat.Average;
|
|
tstRslt.TempDownStart = (float)TempDownStat.First;
|
|
tstRslt.TempDownEnd = (float)TempDownStat.Last;
|
|
tstRslt.TempDownMin = (float)TempDownStat.Min;
|
|
tstRslt.TempDownMax = (float)TempDownStat.Max;
|
|
tstRslt.TempDivMean = (float)TempDivStat.Average;
|
|
tstRslt.TempDivStart = (float)TempDivStat.First;
|
|
tstRslt.TempDivEnd = (float)TempDivStat.Last;
|
|
tstRslt.TempDivMin = (float)TempDivStat.Min;
|
|
tstRslt.TempDivMax = (float)TempDivStat.Max;
|
|
tstRslt.DensityIn = Formulas.WaterDensityFromTempPress(tstRslt.TempUpMean, tstRslt.PressUpMean);
|
|
tstRslt.DensityDiv = Formulas.WaterDensityFromTempPress(tstRslt.TempDivMean, 0);
|
|
tstRslt.DensityLine = Formulas.WaterDensityFromTempPress((tstRslt.TempUpMean + tstRslt.TempDownMean) / 2,
|
|
(tstRslt.PressUpMean + tstRslt.PressDownMean) / 2);
|
|
}
|
|
|
|
|
|
protected string TestResult2CsvLine(string testName, int part)
|
|
{
|
|
Results.Entities.TestRslt tstRslt = ProcessData.BatchRslts.GetTestRslt(testName, part);
|
|
if (tstRslt == null) return string.Empty;
|
|
return TestResult2CsvLine(tstRslt);
|
|
}
|
|
|
|
|
|
protected string TestResult2CsvLine(Results.Entities.TestRslt tstRslt)
|
|
{
|
|
bool isPMaxTest = tstRslt.IsPMaxTest();
|
|
bool isStartStop = tstRslt.IsStartStop();
|
|
bool isDiverter = tstRslt.IsDiverter();
|
|
bool isVolumeMethod = tstRslt.IsVolumeMethod();
|
|
|
|
System.Text.StringBuilder sb = new System.Text.StringBuilder();
|
|
|
|
sb.Append(tstRslt.StartTime); /// A
|
|
sb.Append(";"); sb.Append(tstRslt.Batch.BatchNr); /// B
|
|
|
|
/// Test information, target values, etc.
|
|
sb.Append(";"); sb.Append(tstRslt.Name()); /// C
|
|
sb.Append(";"); sb.Append(tstRslt.Repeats()); /// D
|
|
sb.Append(";"); sb.Append(tstRslt.RepetitionNr); /// E
|
|
sb.Append(";"); sb.Append(tstRslt.Method()); /// F
|
|
sb.Append(";"); sb.Append(tstRslt.TargetVolume()); /// G
|
|
sb.Append(";"); sb.Append(tstRslt.Qfrom()); /// H
|
|
sb.Append(";"); sb.Append(tstRslt.Qto()); /// I
|
|
sb.Append(";"); sb.Append(tstRslt.ErrLimLo() + tstRslt.ErrLimMargin()); /// J
|
|
sb.Append(";"); sb.Append(tstRslt.ErrLimHi() - tstRslt.ErrLimMargin()); /// K
|
|
sb.Append(";"); sb.AppendFormat("{0:F1}", tstRslt.TempLimLo()); /// L
|
|
sb.Append(";"); sb.AppendFormat("{0:F1}", tstRslt.TempLimHi()); /// M
|
|
sb.Append(";"); sb.Append("0"); /// N
|
|
sb.Append(";"); sb.Append("16"); /// O
|
|
sb.Append(";"); sb.Append(tstRslt.RefFlowmeter()); /// P
|
|
sb.Append(";"); sb.AppendFormat("{0:F4}", Formulas.DistilledWaterDensityFromTemp(tstRslt.AmbTempMean)); /// Q [kg/m3] hustota vody pri teplote okolia z priemernej teploty okolia bez korekcie na realnu hustotu vody
|
|
sb.Append(";"); sb.Append((tstRslt.Components != null) ? tstRslt.Components.Scale : string.Empty); /// R
|
|
|
|
/// Ambient
|
|
sb.Append(";"); sb.AppendFormat("{0:F1}", Units.ConvertTo(Unit.C, tstRslt.AmbTempStart)); /// S [°C]
|
|
sb.Append(";"); sb.AppendFormat("{0:F0}", Units.ConvertTo(Unit.mbar, tstRslt.AmbPressStart)); /// T [mbar]
|
|
sb.Append(";"); sb.AppendFormat("{0:F1}", Units.ConvertTo(Unit.RPct, tstRslt.AmbHumiStart)); /// U [R%]
|
|
|
|
/// Pressure
|
|
sb.Append(";"); sb.AppendFormat("{0:F0}", Units.ConvertTo(Unit.kPa, tstRslt.PressUpMean)); /// V [kPa]
|
|
sb.Append(";"); sb.AppendFormat("{0:F0}", Units.ConvertTo(Unit.kPa, tstRslt.PressDownMean)); /// W [kPa]
|
|
sb.Append(";"); sb.AppendFormat("{0:F1}", Units.ConvertTo(Unit.kPa, tstRslt.PressDeltaMean)); /// X [kPa]
|
|
sb.Append(";"); sb.AppendFormat("{0:F0}", Units.ConvertTo(Unit.kPa, tstRslt.PressUpStart)); /// Y [kPa]
|
|
sb.Append(";"); sb.AppendFormat("{0:F0}", Units.ConvertTo(Unit.kPa, tstRslt.PressDownStart)); /// Z [kPa]
|
|
sb.Append(";"); sb.AppendFormat("{0:F1}", Units.ConvertTo(Unit.kPa, tstRslt.PressDeltaStart)); /// AA [kPa]
|
|
sb.Append(";"); sb.AppendFormat("{0:F0}", Units.ConvertTo(Unit.kPa, tstRslt.PressUpEnd)); /// AB [kPa]
|
|
sb.Append(";"); sb.AppendFormat("{0:F0}", Units.ConvertTo(Unit.kPa, tstRslt.PressDownEnd)); /// AC [kPa]
|
|
sb.Append(";"); sb.AppendFormat("{0:F1}", Units.ConvertTo(Unit.kPa, tstRslt.PressDeltaEnd)); /// AD [kPa]
|
|
|
|
/// Temperature
|
|
sb.Append(";"); sb.Append(Units.ConvertTo(Unit.C, tstRslt.TempUpMean)); /// AE [°C]
|
|
sb.Append(";"); sb.Append(Units.ConvertTo(Unit.C, tstRslt.TempDownMean)); /// AF [°C]
|
|
sb.Append(";"); sb.Append(Units.ConvertTo(Unit.C, tstRslt.TempDivMean)); /// AG [°C]
|
|
sb.Append(";"); sb.Append(Units.ConvertTo(Unit.C, tstRslt.Custom1)); /// AH [°C] T hi mean
|
|
sb.Append(";"); sb.Append(Units.ConvertTo(Unit.C, tstRslt.Custom6)); /// AI [°C] T lo mean
|
|
sb.Append(";"); sb.Append(Units.ConvertTo(Unit.C, tstRslt.TempUpStart)); /// AJ [°C]
|
|
sb.Append(";"); sb.Append(Units.ConvertTo(Unit.C, tstRslt.TempDownStart)); /// AK [°C]
|
|
sb.Append(";"); sb.Append(Units.ConvertTo(Unit.C, tstRslt.TempDivStart)); /// AL [°C]
|
|
sb.Append(";"); sb.Append(Units.ConvertTo(Unit.C, tstRslt.Custom2)); /// AM [°C] T hi start
|
|
sb.Append(";"); sb.Append(Units.ConvertTo(Unit.C, tstRslt.Custom7)); /// AN [°C] T lo start
|
|
sb.Append(";"); sb.Append(Units.ConvertTo(Unit.C, tstRslt.TempUpEnd)); /// AO [°C]
|
|
sb.Append(";"); sb.Append(Units.ConvertTo(Unit.C, tstRslt.TempDownEnd)); /// AP [°C]
|
|
sb.Append(";"); sb.Append(Units.ConvertTo(Unit.C, tstRslt.TempDivEnd)); /// AQ [°C]
|
|
sb.Append(";"); sb.Append(Units.ConvertTo(Unit.C, tstRslt.Custom3)); /// AR [°C] T hi end
|
|
sb.Append(";"); sb.Append(Units.ConvertTo(Unit.C, tstRslt.Custom8)); /// AS [°C] T lo end
|
|
|
|
/// Mass
|
|
sb.Append(";"); sb.Append(tstRslt.MassStartRaw); /// AT [kg]
|
|
sb.Append(";"); sb.Append(tstRslt.MassStart); /// AU [kg]
|
|
sb.Append(";"); sb.Append(tstRslt.MassEndRaw); /// AV [kg]
|
|
sb.Append(";"); sb.Append(tstRslt.MassEnd); /// AW [kg]
|
|
sb.Append(";"); sb.Append(tstRslt.MassEnd - tstRslt.MassStart); /// AX [kg]
|
|
|
|
/// Density and buoyancy
|
|
sb.Append(";"); sb.Append(tstRslt.DensityDiv); /// AY [kg/m3]
|
|
sb.Append(";"); sb.Append((tstRslt.TempUpMean + tstRslt.TempDownMean) / 2); /// AZ [°C] Tline ... priemerna teplota v linii
|
|
sb.Append(";"); sb.Append(tstRslt.DensityLine); /// BA [kg/m3]
|
|
sb.Append(";"); sb.Append(tstRslt.MassOfEvapWater); /// BB [kg] mass of evaporated water
|
|
sb.Append(";"); sb.Append(tstRslt.Batch.Buoyancy); /// BC Buoyancy: Sheet1 - X9
|
|
|
|
sb.Append(";"); sb.Append(tstRslt.Batch.SampleDensity); /// BD
|
|
sb.Append(";"); sb.Append(tstRslt.Batch.SampleTemp); /// BE
|
|
sb.Append(";"); sb.Append(tstRslt.FlowMax); /// BF pipe expansion: teraz vynechat
|
|
sb.Append(";"); sb.Append(tstRslt.FlowMin); /// BG [kg/h] Qm
|
|
sb.Append(";"); sb.Append(tstRslt.Flow); /// BH [l/h] Qv
|
|
sb.Append(";"); sb.Append(tstRslt.VolumeCTV); /// BI [l] Vet .... komercne prava hodnota objemu - podla vahy
|
|
sb.Append(";"); sb.Append(tstRslt.VolumeMaster); /// BJ [l] Velm ... objem podla etalonu (Prolonged: objem do vahy podla impulzov hradlovanych klapkou)
|
|
sb.Append(";"); sb.Append(tstRslt.TestTimeCorrection); /// BK [s] test time correction (diverter correction)
|
|
/// (ori.) BK [l] Vmass .. objem podla druheho etalonu / prietokomeru pred tratou (teraz vynechavame)
|
|
sb.Append(";"); sb.Append(tstRslt.TestTime); /// BL [s]
|
|
|
|
sb.Append(";"); sb.Append(isVolumeMethod ? Formulas.ErrorFromVolumes(tstRslt.ConstMasterCorr, tstRslt.ConstMasterRaw) : tstRslt.ErrorMaster);
|
|
/// BM [%] Eelm .... chyba etalonu voci komercne pravej hodnote
|
|
sb.Append(";"); sb.Append(" "); /// BN [%] Emass ... chyba druheho etalonu voci komercne pravej hodnote (teraz vynechavame)
|
|
sb.Append(";"); sb.Append((tstRslt.ConstMasterRaw != 0) ? (1 / tstRslt.ConstMasterRaw) : 0); /// BO [pls/l] Const.MID .. konstanta etalonu
|
|
sb.Append(";"); sb.Append(" "); /// BP [pls/l] Const.MA ... konstanta druheho etalonu
|
|
|
|
sb.Append(";"); sb.AppendFormat("{0:F0}", isDiverter ? 1000.0F * tstRslt.DiverterStart : 0); /// BQ [ms] Diverter start time
|
|
sb.Append(";"); sb.AppendFormat("{0:F0}", isDiverter ? 1000.0F * tstRslt.DiverterEnd : 0); /// BR [ms] Diverter end time
|
|
sb.Append(";"); sb.AppendFormat("{0:F0}", isStartStop ? 1000.0F * tstRslt.DiverterStart : 0); /// BS [ms] Start valve open time
|
|
sb.Append(";"); sb.AppendFormat("{0:F0}", isStartStop ? 1000.0F * tstRslt.DiverterEnd : 0); /// BT [ms] Start valve close time
|
|
sb.Append(";"); sb.Append(tstRslt.TempUpMax); /// BU [°C]
|
|
sb.Append(";"); sb.Append(tstRslt.TempDownMax); /// BV [°C]
|
|
sb.Append(";"); sb.Append(tstRslt.TempUpMin); /// BW [°C]
|
|
sb.Append(";"); sb.Append(tstRslt.TempDownMin); /// BX [°C]
|
|
sb.Append(";"); sb.Append(isPMaxTest ? tstRslt.TestTime : 0); /// BY [s] Duration of the pressure test
|
|
sb.Append(";"); sb.AppendFormat("{0:F1}", Units.ConvertTo(Unit.C, tstRslt.AmbTempEnd)); /// BZ [°C]
|
|
sb.Append(";"); sb.AppendFormat("{0:F0}", Units.ConvertTo(Unit.mbar, tstRslt.AmbPressEnd)); /// CA [mbar]
|
|
sb.Append(";"); sb.AppendFormat("{0:F1}", Units.ConvertTo(Unit.RPct, tstRslt.AmbHumiEnd)); /// CB [R%]
|
|
|
|
sb.Append(";"); sb.Append(tstRslt.PulsesMaster); /// CC Celkovy pocet et. pulzov skusky (Prolonged : do vahy)
|
|
//sb.Append(";"); sb.Append((tstRslt.TotalPulsesMstr != 0) ? tstRslt.TotalPulsesMstr.ToString() : " "); /// CD - '' - pre druhy (Prolonged : celkovy pocet)
|
|
sb.Append(";"); sb.Append(1000 * tstRslt.TestTimeCorrection); /// CD [ms] Diverter test time correction
|
|
|
|
var smryItems = DEItem.GetSummaryColumns();
|
|
|
|
for (int i = 0; i < BatchRslts.Batch.WaterMeters.Count; i++)
|
|
{
|
|
if (BatchRslts.Batch.WaterMeters != null &&
|
|
BatchRslts.Batch.WaterMeters.Count > i &&
|
|
BatchRslts.Batch.WaterMeters[i] != null)
|
|
{
|
|
bool Disabled = BatchRslts.Batch.WaterMeters[i].Disabled;
|
|
bool bChanel = false;
|
|
if (Disabled &&
|
|
BatchRslts.Batch.WaterMeters[i].SerialNr != null &&
|
|
BatchRslts.Batch.WaterMeters[i].SerialNr.Contains("_CH")) //write channels
|
|
{
|
|
Disabled = false;
|
|
bChanel = true;
|
|
}
|
|
|
|
if (Disabled)
|
|
continue;
|
|
|
|
var wm = BatchRslts.Batch.WaterMeters[i];
|
|
|
|
if (!wm.Compound() && !wm.HeatMeter())
|
|
{
|
|
/// If this is a single meter
|
|
Results.Entities.MeterTestRslt mtrRslt = null;
|
|
bool wmDisabled = wm.Disabled;
|
|
try
|
|
{
|
|
wm.Disabled = false;
|
|
if (!bChanel)
|
|
mtrRslt = ProcessData.BatchRslts.GetMeterTestRslt(tstRslt.Name(), i, CompoundMeterId.Single);
|
|
else
|
|
{
|
|
mtrRslt = wm.GetMeterTestRslt(tstRslt.Name(), CompoundMeterId.Single);
|
|
}
|
|
}
|
|
catch (Exception ex) { }
|
|
finally
|
|
{
|
|
wm.Disabled = wmDisabled;
|
|
}
|
|
|
|
if (mtrRslt != null)
|
|
{
|
|
bool isCamera = (mtrRslt.RegReaderType == (int)RegisterReaderType.Camera);
|
|
|
|
sb.Append(";"); sb.Append(wm.SerialNr);/// CE WM Ser.No.
|
|
sb.Append(";"); sb.Append(mtrRslt.VolumeStart); /// CF WM Vstart - pociatocny stav pri pevnom starte alebo zachyteny pri data streame
|
|
sb.Append(";"); sb.Append(mtrRslt.VolumeEnd); /// CG WM Vend - konecny stav pri pevnom starte alebo zachyteny pri data streame
|
|
sb.Append(";"); sb.Append(mtrRslt.VolumeMeter); /// CH WM Vmer - objem namerany vodomerom
|
|
sb.Append(";"); sb.Append(mtrRslt.VolumeRef); /// CI WM Vref - objem namerany stanicou
|
|
sb.Append(";"); sb.Append(mtrRslt.Error); /// CJ WM Emt - chyba vodomerom nameraneho objemu
|
|
#if IPERL
|
|
sb.Append(";"); sb.Append(wm.CalibFactor); /// CK iPerl calibration factor used during the test / ...
|
|
#else
|
|
sb.Append(";"); sb.Append(" "); /// CK nechat prazdne
|
|
#endif
|
|
sb.Append(";"); sb.Append(mtrRslt.PulsesMeter); /// CL WM Np met - pocet impulzov zo skusaneho meradla
|
|
sb.Append(";"); sb.Append(mtrRslt.PulsesMaster); /// CM WM Np elm - pocet impulzov etalonu pocas merania pre prislusny vodomer
|
|
sb.Append(";"); sb.Append(mtrRslt.TestTime); /// CN WM Tmet - cas merania (obmedzany pri synchro skuske)
|
|
sb.Append(";"); sb.Append(mtrRslt.Passed ? "OK" : "NOK"); /// CO WM Vysledok (t.j. ci je v hraniciach chyb) - OK/NOK
|
|
#if IPERL
|
|
sb.Append(";"); sb.Append(mtrRslt.WaterMeter.Q2CorrRL); /// CP iPerl Q2 correction factor used during the test / AN value - hodnota z analogoveho prevodnika
|
|
#else
|
|
sb.Append(";"); sb.Append(mtrRslt.PulsesPerLiter); /// CP Pulses per liter
|
|
#endif
|
|
sb.Append(";"); sb.Append(isCamera
|
|
? mtrRslt.VolumeStart * mtrRslt.PulsesPerLiter /// CQ WM Phi_start (pri hodnotach z kamery)
|
|
: wm.WMPosition); /// CQ WMPosition (normalne)
|
|
sb.Append(";"); sb.Append(isCamera
|
|
? mtrRslt.VolumeEnd * mtrRslt.PulsesPerLiter /// CR WM Phi_end (pri hodnotach z kamery)
|
|
: 0); /// CR not used/spare (normalne)
|
|
|
|
sb.Append(";"); sb.Append(mtrRslt.TimestampStart); /// CS WM Time_start - ' ' -
|
|
sb.Append(";"); sb.Append(mtrRslt.TimestampEnd); /// CT WM Time_end - ' ' -
|
|
|
|
//sb.Append(";"); sb.Append(isCamera ? mtrRslt.PulsesPerLiter : 0); /// CU camera: WM Degree per liter
|
|
sb.Append(";"); sb.Append(smryItems.Count < 1 ? "0" : DEUtils.GetContent(smryItems[0].Content, wm)); /// CU
|
|
sb.Append(";"); sb.Append(smryItems.Count < 2 ? "0" : DEUtils.GetContent(smryItems[1].Content, wm)); /// CV
|
|
sb.Append(";"); sb.Append(smryItems.Count < 3 ? "0" : DEUtils.GetContent(smryItems[2].Content, wm)); /// CW
|
|
sb.Append(";"); sb.Append(smryItems.Count < 4 ? "0" : DEUtils.GetContent(smryItems[3].Content, wm)); /// CX
|
|
sb.Append(";"); sb.Append(smryItems.Count < 5 ? "0" : DEUtils.GetContent(smryItems[4].Content, wm)); /// CY
|
|
}
|
|
}
|
|
else if (wm.Compound())
|
|
{
|
|
/// Else if this is a compound meter
|
|
|
|
for (byte b = (byte)CompoundMeterId.CompoundMain; b <= (byte)CompoundMeterId.Compound; b++)
|
|
{
|
|
var mtrRslt = ProcessData.BatchRslts.GetMeterTestRslt(tstRslt.Name(), i, (CompoundMeterId)b);
|
|
|
|
if (mtrRslt != null)
|
|
{
|
|
sb.Append(";");
|
|
switch ((CompoundMeterId)b)
|
|
{
|
|
case CompoundMeterId.CompoundMain:
|
|
sb.Append(wm.SerialNr); /// CE
|
|
break;
|
|
case CompoundMeterId.CompoundAux:
|
|
sb.Append(wm.SerialNrAux); /// CE
|
|
break;
|
|
case CompoundMeterId.Compound:
|
|
sb.Append(wm.SerialNr); /// CE
|
|
break;
|
|
}
|
|
sb.Append(";"); sb.Append(mtrRslt.VolumeStart); /// CF WM Vinit - pri pevnom starte pociatocny stav natukany alebo cez inteligentny system
|
|
sb.Append(";"); sb.Append(mtrRslt.VolumeEnd); /// CG WM Vfin - pri pevnom starte konecny stav natukany alebo cez inteligentny system
|
|
sb.Append(";"); sb.Append(mtrRslt.VolumeMeter); /// CH WM Vmer - objem namerany vodomerom
|
|
sb.Append(";"); sb.Append(mtrRslt.VolumeRef); /// CI WM Vet - objem namerany stanicou
|
|
sb.Append(";"); sb.Append(mtrRslt.Error); /// CJ WM Emt - chyba vodomerom nameraneho objemu
|
|
sb.Append(";"); sb.Append(" "); /// CK WM U - neistota (zatial nechat prazdne)
|
|
sb.Append(";"); sb.Append(mtrRslt.PulsesMeter); /// CL WM Np met - pocet impulzov zo skusaneho meradla
|
|
sb.Append(";"); sb.Append(mtrRslt.PulsesMaster); /// CM WM Np elm - pocet impulzov etalonu pocas merania pre prislusny vodomer
|
|
sb.Append(";"); sb.Append(mtrRslt.TestTime); /// CN WM Tmet - cas merania (obmedzany pri synchro skuske)
|
|
sb.Append(";"); sb.Append(mtrRslt.Passed ? "OK" : "NOK"); /// CO WM Vysledok (t.j. ci je v hraniciach chyb) - OK/NOK
|
|
sb.Append(";"); sb.Append(" "); /// CP WM AN value - hodnota z analogoveho prevodnika (teraz nic)
|
|
|
|
bool isCamera = mtrRslt.IsCamera();
|
|
sb.Append(";"); sb.Append(isCamera
|
|
? mtrRslt.VolumeStart * mtrRslt.PulsesPerLiter /// CQ WM Phi_start (pri hodnotach z kamery)
|
|
: wm.WMPosition); /// CQ WMPosition (normalne)
|
|
sb.Append(";"); sb.Append(isCamera
|
|
? mtrRslt.VolumeEnd * mtrRslt.PulsesPerLiter /// CR WM Phi_end (pri hodnotach z kamery)
|
|
: 0); /// CR not used/spare (normalne)
|
|
sb.Append(";"); sb.Append(isCamera ? mtrRslt.TimestampStart : 0); /// CS WM Time_start - ' ' -
|
|
sb.Append(";"); sb.Append(isCamera ? mtrRslt.TimestampEnd : 0); /// CT WM Time_end - ' ' -
|
|
sb.Append(";"); sb.Append(isCamera ? mtrRslt.PulsesPerLiter : 0); /// CU WM Degree per liter
|
|
|
|
sb.Append(";"); sb.Append(0); /// CV Analog out 1 (max mA)
|
|
sb.Append(";"); sb.Append(0); /// CW Analog out 2 (V)
|
|
sb.Append(";"); sb.Append(0); /// CX Analog out 3 (min mA)
|
|
sb.Append(";"); sb.Append(0); /// CY Analog out 4 (max Q)
|
|
}
|
|
}
|
|
}
|
|
else /// if (ProcessData.BatchRslts.WaterMeters[i].HeatMeter())
|
|
{
|
|
/// Else this is a heat meter
|
|
|
|
var volumeMtr = ProcessData.BatchRslts.GetMeterTestRslt(tstRslt.Name(), i, CompoundMeterId.HeatMeterVolume);
|
|
var energyMtr = ProcessData.BatchRslts.GetMeterTestRslt(tstRslt.Name(), i, CompoundMeterId.HeatMeterEnergy);
|
|
|
|
if (volumeMtr != null)
|
|
{
|
|
sb.Append(";"); sb.Append(wm.SerialNr); /// WM Ser.No.
|
|
sb.Append(";"); sb.Append(volumeMtr.VolumeStart); /// WM Vstart - pociatocny stav pri pevnom starte alebo zachyteny pri data streame
|
|
sb.Append(";"); sb.Append(volumeMtr.VolumeEnd); /// WM Vend - konecny stav pri pevnom starte alebo zachyteny pri data streame
|
|
sb.Append(";"); sb.Append(volumeMtr.VolumeMeter); /// WM Vmer - objem namerany vodomerom
|
|
sb.Append(";"); sb.Append(volumeMtr.VolumeRef); /// WM Vref - objem namerany stanicou
|
|
sb.Append(";"); sb.Append(volumeMtr.Error); /// WM Emt - chyba vodomerom nameraneho objemu
|
|
#if IPERL
|
|
sb.Append(";"); sb.Append(wm.CalibFactor); /// iPerl calibration factor used during the test / ...
|
|
#else
|
|
sb.Append(";"); sb.Append(" "); /// nechat prazdne
|
|
#endif
|
|
sb.Append(";"); sb.Append(volumeMtr.PulsesMeter); /// WM Np met - pocet impulzov zo skusaneho meradla
|
|
sb.Append(";"); sb.Append(volumeMtr.PulsesMaster); /// WM Np elm - pocet impulzov etalonu pocas merania pre prislusny vodomer
|
|
sb.Append(";"); sb.Append(volumeMtr.TestTime); /// WM Tmet - cas merania (obmedzany pri synchro skuske)
|
|
sb.Append(";"); sb.Append(volumeMtr.Passed ? "OK" : "NOK"); /// WM Vysledok (t.j. ci je v hraniciach chyb) - OK/NOK
|
|
#if IPERL
|
|
sb.Append(";"); sb.Append(volumeMtr.WaterMeter.Q2CorrRL); /// iPerl Q2 correction factor used during the test / AN value - hodnota z analogoveho prevodnika
|
|
#else
|
|
sb.Append(";"); sb.Append(" "); /// nechat prazdne
|
|
#endif
|
|
sb.Append(";"); sb.Append(volumeMtr.VolumeStart); /// WM Volume_start - pri datastreamovych hodnotach (alebo kamera)
|
|
sb.Append(";"); sb.Append(volumeMtr.TimestampStart); /// WM Time_start - ' ' -
|
|
sb.Append(";"); sb.Append(volumeMtr.VolumeEnd); /// WM Volume_end - ' ' -
|
|
sb.Append(";"); sb.Append(volumeMtr.TimestampEnd); /// WM Time_end - ' ' -
|
|
}
|
|
|
|
if (energyMtr != null)
|
|
{
|
|
sb.Append(";"); sb.Append(wm.SerialNr); /// WM Ser.No.
|
|
sb.Append(";"); sb.Append(energyMtr.VolumeStart); /// WM Vstart - pociatocny stav pri pevnom starte alebo zachyteny pri data streame
|
|
sb.Append(";"); sb.Append(energyMtr.VolumeEnd); /// WM Vend - konecny stav pri pevnom starte alebo zachyteny pri data streame
|
|
sb.Append(";"); sb.Append(energyMtr.VolumeMeter); /// WM Vmer - objem namerany vodomerom
|
|
sb.Append(";"); sb.Append(energyMtr.VolumeRef); /// WM Vref - objem namerany stanicou
|
|
sb.Append(";"); sb.Append(energyMtr.Error); /// WM Emt - chyba vodomerom nameraneho objemu
|
|
#if IPERL
|
|
sb.Append(";"); sb.Append(wm.CalibFactor); /// iPerl calibration factor used during the test / ...
|
|
#else
|
|
sb.Append(";"); sb.Append(" "); /// nechat prazdne
|
|
#endif
|
|
sb.Append(";"); sb.Append(energyMtr.PulsesMeter); /// WM Np met - pocet impulzov zo skusaneho meradla
|
|
sb.Append(";"); sb.Append(energyMtr.PulsesMaster); /// WM Np elm - pocet impulzov etalonu pocas merania pre prislusny vodomer
|
|
sb.Append(";"); sb.Append(energyMtr.TestTime); /// WM Tmet - cas merania (obmedzany pri synchro skuske)
|
|
sb.Append(";"); sb.Append(energyMtr.Passed ? "OK" : "NOK"); /// WM Vysledok (t.j. ci je v hraniciach chyb) - OK/NOK
|
|
#if IPERL
|
|
sb.Append(";"); sb.Append(energyMtr.WaterMeter.Q2CorrRL); /// iPerl Q2 correction factor used during the test / AN value - hodnota z analogoveho prevodnika
|
|
#else
|
|
sb.Append(";"); sb.Append(" "); /// nechat prazdne
|
|
#endif
|
|
sb.Append(";"); sb.Append(energyMtr.VolumeStart); /// WM Volume_start - pri datastreamovych hodnotach (alebo kamera)
|
|
sb.Append(";"); sb.Append(energyMtr.TimestampStart); /// WM Time_start - ' ' -
|
|
sb.Append(";"); sb.Append(energyMtr.VolumeEnd); /// WM Volume_end - ' ' -
|
|
sb.Append(";"); sb.Append(energyMtr.TimestampEnd); /// WM Time_end - ' ' -
|
|
}
|
|
}
|
|
}
|
|
}
|
|
sb.Append(";");
|
|
|
|
return sb.ToString();
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Create a simulated test result (single meter).
|
|
/// </summary>
|
|
/// <param name="test">Test to be simulated</param>
|
|
/// <returns>Test result</returns>
|
|
public void MakeSimulatedTrivial(Config.Entities.Test test, int repetitionNr, int part)
|
|
{
|
|
string fullTestName = Results.Utils.GetTestName(test.Name, test.Repeats, repetitionNr);
|
|
|
|
Results.Entities.TestRslt tstRslt = ProcessData.BatchRslts.GetTestRslt(fullTestName, part);
|
|
Results.Utils.GetCounterStates(tstRslt, Program.LocalSettings.Counters);
|
|
|
|
if (tstRslt == null) return; /// Prevent program crash in certain cases
|
|
|
|
tstRslt.AmbTempMean = 20.0f;
|
|
tstRslt.AmbPressMean = 1.0f;
|
|
tstRslt.AmbHumiMean = 50.0f;
|
|
tstRslt.PressUpStart = 1.0f;
|
|
tstRslt.PressDownStart = 1.0f;
|
|
tstRslt.TempUpStart = 20.0f;
|
|
tstRslt.TempDownStart = 20.0f;
|
|
tstRslt.TempDivStart = 20.0f;
|
|
tstRslt.PressUpEnd = 1.0f;
|
|
tstRslt.PressDownEnd = 1.0f;
|
|
tstRslt.TempUpEnd = 20.0f;
|
|
tstRslt.TempDownEnd = 20.0f;
|
|
tstRslt.TempDivEnd = 20.0f;
|
|
tstRslt.PressUpMean = 1.0f;
|
|
tstRslt.PressDownMean = 1.0f;
|
|
tstRslt.TempUpMean = 20.0f;
|
|
tstRslt.TempDownMean = 20.0f;
|
|
tstRslt.TempDivMean = 20.0f;
|
|
tstRslt.PressUpMin = 1.0f;
|
|
tstRslt.PressDownMin = 1.0f;
|
|
tstRslt.TempUpMin = 20.0f;
|
|
tstRslt.TempDownMin = 20.0f;
|
|
tstRslt.TempDivMin = 20.0f;
|
|
tstRslt.PressUpMax = 1.0f;
|
|
tstRslt.PressDownMax = 1.0f;
|
|
tstRslt.TempUpMax = 20.0f;
|
|
tstRslt.TempDownMax = 20.0f;
|
|
tstRslt.TempDivMax = 20.0f;
|
|
tstRslt.ConductMin = Conductivity.Val;
|
|
tstRslt.ConductMax = Conductivity.Val;
|
|
|
|
tstRslt.DensityIn = Formulas.RealDensity();
|
|
tstRslt.DensityLine = Formulas.RealDensity();
|
|
tstRslt.DensityDiv = Formulas.RealDensity();
|
|
|
|
double flowMeterLtrPerPulse = outPath.FlowMeter?.LtrPerPulse ?? 1;
|
|
|
|
tstRslt.MethodClass = TbfComponents.FindComponent(test.Method).ClassName;
|
|
tstRslt.StartTime = DateTime.Now;
|
|
tstRslt.EndTime = DateTime.Now + new TimeSpan(0, 0, 1);
|
|
tstRslt.FlowSetTime = 10;
|
|
tstRslt.TestTime = tstRslt.TargetTime();
|
|
tstRslt.PulsesMaster = (flowMeterLtrPerPulse > 1E-6) ? (1.0075 * tstRslt.TargetVolume() / flowMeterLtrPerPulse) : 1;
|
|
tstRslt.MassStartRaw = 0;
|
|
tstRslt.MassStart = MeasurementCorrection.CorrectedValue(tstRslt.MassStartRaw, outPath.Scale.Corrections);
|
|
tstRslt.MassEndRaw = tstRslt.TargetVolume() * Formulas.RealDensity() / 1000.0f;
|
|
tstRslt.MassEnd = MeasurementCorrection.CorrectedValue(tstRslt.MassEndRaw, outPath.Scale.Corrections);
|
|
tstRslt.Flow = 3.6 * flowMeterLtrPerPulse * tstRslt.PulsesMaster / tstRslt.TestTime;
|
|
tstRslt.MassOfEvapWater = 0;
|
|
tstRslt.VolumeCTV = 1000 * tstRslt.Batch.Buoyancy * (tstRslt.MassEnd - tstRslt.MassStart) / tstRslt.DensityLine; /// [l] commercially true volume
|
|
tstRslt.VolumeMaster = flowMeterLtrPerPulse * tstRslt.PulsesMaster; /// [l] volume from the master flow meter
|
|
tstRslt.ConstMasterRaw = flowMeterLtrPerPulse; /// Uncorrected master flowmeter coefficient
|
|
tstRslt.ConstMasterCorr = outPath.FlowMeter?.LtrPerPulseCorrected(tstRslt.Flow, tstRslt.TempDownMean) ?? 1; /// Corrected master pulses per liter
|
|
tstRslt.ConstMaster = (tstRslt.VolumeMaster == 0) ? tstRslt.ConstMasterCorr : (flowMeterLtrPerPulse * tstRslt.VolumeCTV / tstRslt.VolumeMaster);
|
|
|
|
tstRslt.ErrorMaster = Formulas.ErrorFromVolumes(tstRslt.VolumeMaster, tstRslt.VolumeCTV);
|
|
|
|
tstRslt.FlowMean = (float)RefFlowStat.Average;
|
|
tstRslt.FlowStart = (float)RefFlowStat.First;
|
|
tstRslt.FlowEnd = (float)RefFlowStat.Last;
|
|
tstRslt.FlowMin = (float)RefFlowStat.Min;
|
|
tstRslt.FlowMax = (float)RefFlowStat.Max;
|
|
|
|
for (int i = 0; i < BatchRslts.WMPositionsCount; i++)
|
|
{
|
|
float errorPct = 0;
|
|
|
|
Results.Entities.MeterTestRslt meterRslt = ProcessData.BatchRslts.GetMeterTestRslt(fullTestName, i, CompoundMeterId.Single);
|
|
IRegReader regReader = sensPath.RegisterReaders[i];
|
|
|
|
if (meterRslt != null && regReader != null)
|
|
{
|
|
meterRslt.VolumeMeter = tstRslt.TargetVolume() * (1.0 + 0.01 * errorPct);
|
|
|
|
meterRslt.PulsesMeter = regReader.PulsesPerLtr * meterRslt.VolumeMeter;
|
|
meterRslt.PulsesMaster = tstRslt.PulsesMaster;
|
|
meterRslt.PulsesPerLiter = regReader.PulsesPerLtr;
|
|
meterRslt.VolumeStart = 0;
|
|
meterRslt.VolumeEnd = meterRslt.VolumeMeter;
|
|
meterRslt.VolumeRef = tstRslt.TargetVolume();
|
|
meterRslt.TimestampStart = 0;
|
|
meterRslt.TimestampEnd = tstRslt.TargetTime();
|
|
meterRslt.TestTime = tstRslt.TargetTime();
|
|
meterRslt.Error = errorPct;
|
|
meterRslt.Passed = true;
|
|
meterRslt.TestDone = true;
|
|
tstRslt.TestDone = true;
|
|
}
|
|
}
|
|
|
|
tstRslt.Components = Results.Entities.Components
|
|
.UpdateList(BatchRslts.ComponentsList,
|
|
new Results.Entities.Components((BenchInfo != null) ? BenchInfo.TestBenchId : 1,
|
|
(BenchInfo != null) ? BenchInfo.TestBenchName : "testbench",
|
|
inPath.Pump != null ? inPath.Pump.Name : string.Empty,
|
|
outPath.FlowMeter != null ? outPath.FlowMeter.Name : string.Empty,
|
|
outPath.Scale != null ? outPath.Scale.Name : string.Empty,
|
|
outPath.RegValve != null ? outPath.RegValve.Name : string.Empty,
|
|
outPath.Diverter != null ? outPath.Diverter.Name : string.Empty));
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Create a simulated test result (single meter).
|
|
/// </summary>
|
|
/// <param name="test">Test to be simulated</param>
|
|
/// <returns>Test result</returns>
|
|
protected void MakeSimulated(Config.Entities.Test test, int repetitionNr, int part, float errorPctBase)
|
|
{
|
|
string fullTestName = Results.Utils.GetTestName(test.Name, test.Repeats, repetitionNr);
|
|
|
|
Results.Entities.TestRslt tstRslt = ProcessData.BatchRslts.GetTestRslt(fullTestName, part);
|
|
Results.Utils.GetCounterStates(tstRslt, Program.LocalSettings.Counters);
|
|
|
|
if (tstRslt == null) return; /// Prevent program crash in certain cases
|
|
|
|
tstRslt.AmbTempMean = 20.0f;
|
|
tstRslt.AmbPressMean = 1.0f;
|
|
tstRslt.AmbHumiMean = 50.0f;
|
|
tstRslt.PressUpStart = 1.0f;
|
|
tstRslt.PressDownStart = 1.0f;
|
|
tstRslt.TempUpStart = 20.0f;
|
|
tstRslt.TempDownStart = 20.0f;
|
|
tstRslt.TempDivStart = 20.0f;
|
|
tstRslt.PressUpEnd = 1.0f;
|
|
tstRslt.PressDownEnd = 1.0f;
|
|
tstRslt.TempUpEnd = 20.0f;
|
|
tstRslt.TempDownEnd = 20.0f;
|
|
tstRslt.TempDivEnd = 20.0f;
|
|
tstRslt.PressUpMean = 1.0f;
|
|
tstRslt.PressDownMean = 1.0f;
|
|
tstRslt.TempUpMean = 20.0f;
|
|
tstRslt.TempDownMean = 20.0f;
|
|
tstRslt.TempDivMean = 20.0f;
|
|
tstRslt.PressUpMin = 1.0f;
|
|
tstRslt.PressDownMin = 1.0f;
|
|
tstRslt.TempUpMin = 20.0f;
|
|
tstRslt.TempDownMin = 20.0f;
|
|
tstRslt.TempDivMin = 20.0f;
|
|
tstRslt.PressUpMax = 1.0f;
|
|
tstRslt.PressDownMax = 1.0f;
|
|
tstRslt.TempUpMax = 20.0f;
|
|
tstRslt.TempDownMax = 20.0f;
|
|
tstRslt.TempDivMax = 20.0f;
|
|
tstRslt.ConductMin = Conductivity.Val;
|
|
tstRslt.ConductMax = Conductivity.Val;
|
|
|
|
tstRslt.DensityIn = Formulas.RealDensity();
|
|
tstRslt.DensityLine = Formulas.RealDensity();
|
|
tstRslt.DensityDiv = Formulas.RealDensity();
|
|
|
|
tstRslt.MethodClass = TbfComponents.FindComponent(test.Method).ClassName;
|
|
tstRslt.StartTime = DateTime.Now;
|
|
tstRslt.EndTime = DateTime.Now + new TimeSpan(0,0,1);
|
|
tstRslt.FlowSetTime = 10;
|
|
tstRslt.TestTime = tstRslt.TargetTime();
|
|
tstRslt.PulsesMaster = (outPath.FlowMeter.LtrPerPulse > 1E-6) ? (1.0075 * tstRslt.TargetVolume() / outPath.FlowMeter.LtrPerPulse) : 1;
|
|
tstRslt.MassStartRaw = 0;
|
|
tstRslt.MassStart = MeasurementCorrection.CorrectedValue(tstRslt.MassStartRaw, outPath.Scale.Corrections);
|
|
tstRslt.MassEndRaw = tstRslt.TargetVolume() * Formulas.RealDensity() / 1000.0f;
|
|
tstRslt.MassEnd = MeasurementCorrection.CorrectedValue(tstRslt.MassEndRaw, outPath.Scale.Corrections);
|
|
tstRslt.Flow = 3.6 * outPath.FlowMeter.LtrPerPulse * tstRslt.PulsesMaster / tstRslt.TestTime;
|
|
tstRslt.MassOfEvapWater = 0;
|
|
tstRslt.VolumeCTV = 1000 * tstRslt.Batch.Buoyancy * (tstRslt.MassEnd - tstRslt.MassStart) / tstRslt.DensityLine;
|
|
/// [l] commercially true volume
|
|
tstRslt.VolumeMaster = outPath.FlowMeter.LtrPerPulse * tstRslt.PulsesMaster; /// [l] volume from the master flow meter
|
|
tstRslt.ConstMasterRaw = outPath.FlowMeter.LtrPerPulse; /// Uncorrected master flowmeter coefficient
|
|
tstRslt.ConstMasterCorr = outPath.FlowMeter.LtrPerPulseCorrected(tstRslt.Flow, tstRslt.TempDownMean);
|
|
/// Corrected master pulses per liter
|
|
tstRslt.ConstMaster = (tstRslt.VolumeMaster == 0) ? tstRslt.ConstMasterCorr : (outPath.FlowMeter.LtrPerPulse * tstRslt.VolumeCTV / tstRslt.VolumeMaster);
|
|
|
|
tstRslt.ErrorMaster = Formulas.ErrorFromVolumes(tstRslt.VolumeMaster, tstRslt.VolumeCTV);
|
|
|
|
tstRslt.FlowMean = (float)RefFlowStat.Average;
|
|
tstRslt.FlowStart = (float)RefFlowStat.First;
|
|
tstRslt.FlowEnd = (float)RefFlowStat.Last;
|
|
tstRslt.FlowMin = (float)RefFlowStat.Min;
|
|
tstRslt.FlowMax = (float)RefFlowStat.Max;
|
|
|
|
for (int i = 0; i < BatchRslts.WMPositionsCount; i++)
|
|
{
|
|
float errorPct = errorPctBase + 0.05f * i;
|
|
|
|
Results.Entities.MeterTestRslt meterRslt = ProcessData.BatchRslts.GetMeterTestRslt(fullTestName, i, CompoundMeterId.Single);
|
|
IRegReader regReader = sensPath.RegisterReaders[i];
|
|
|
|
if (meterRslt != null && regReader != null)
|
|
{
|
|
meterRslt.VolumeMeter = tstRslt.TargetVolume() * (1.0 + 0.01 * errorPct);
|
|
|
|
meterRslt.PulsesMeter = regReader.PulsesPerLtr * meterRslt.VolumeMeter;
|
|
meterRslt.PulsesMaster = tstRslt.PulsesMaster;
|
|
meterRslt.PulsesPerLiter = regReader.PulsesPerLtr;
|
|
meterRslt.VolumeStart = 0;
|
|
meterRslt.VolumeEnd = meterRslt.VolumeMeter;
|
|
meterRslt.VolumeRef = tstRslt.TargetVolume();
|
|
meterRslt.TimestampStart = 0;
|
|
meterRslt.TimestampEnd = tstRslt.TargetTime();
|
|
meterRslt.TestTime = tstRslt.TargetTime();
|
|
meterRslt.Error = errorPct;
|
|
meterRslt.Passed = (errorPct >= tstRslt.ErrLimLo() + tstRslt.ErrLimMargin())
|
|
&& (errorPct <= tstRslt.ErrLimHi() - tstRslt.ErrLimMargin());
|
|
meterRslt.TestDone = true;
|
|
tstRslt.TestDone = true;
|
|
}
|
|
}
|
|
|
|
tstRslt.Components = Results.Entities.Components
|
|
.UpdateList(BatchRslts.ComponentsList,
|
|
new Results.Entities.Components((BenchInfo != null) ? BenchInfo.TestBenchId : 1,
|
|
(BenchInfo != null) ? BenchInfo.TestBenchName : "testbench",
|
|
inPath.Pump != null ? inPath.Pump.Name : string.Empty,
|
|
outPath.FlowMeter != null ? outPath.FlowMeter.Name : string.Empty,
|
|
outPath.Scale != null ? outPath.Scale.Name : string.Empty,
|
|
outPath.RegValve != null ? outPath.RegValve.Name : string.Empty,
|
|
outPath.Diverter != null ? outPath.Diverter.Name : string.Empty));
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Create a simulated test result (compound meter).
|
|
/// </summary>
|
|
/// <param name="test">Test to be simulated</param>
|
|
/// <returns>Test result</returns>
|
|
protected void MakeSimulatedCompound(Config.Entities.Test test, int repetitionNr, int part, float errorPct, float mainPart)
|
|
{
|
|
string fullTestName = Results.Utils.GetTestName(test.Name, test.Repeats, repetitionNr);
|
|
|
|
Results.Entities.TestRslt tstRslt = ProcessData.BatchRslts.GetTestRslt(fullTestName, part);
|
|
|
|
if (tstRslt == null) return; /// Prevent program crash in certain cases
|
|
|
|
tstRslt.MethodClass = TbfComponents.FindComponent(test.Method).ClassName;
|
|
tstRslt.StartTime = DateTime.Now;
|
|
tstRslt.EndTime = DateTime.Now + new TimeSpan(0, 0, 1);
|
|
tstRslt.FlowSetTime = 10;
|
|
tstRslt.TestTime = tstRslt.TargetTime();
|
|
/// TODO: Verify whether 'ltrPerRefPulse' is up to date
|
|
tstRslt.ConstMasterRaw = outPath.FlowMeter.LtrPerPulse;
|
|
tstRslt.ConstMaster = outPath.FlowMeter.LtrPerPulse;
|
|
tstRslt.PulsesMaster = (tstRslt.ConstMasterRaw > 1E-6) ? (tstRslt.TargetVolume() / tstRslt.ConstMasterRaw) : 1;
|
|
tstRslt.MassStartRaw = 0;
|
|
tstRslt.MassStart = 0;
|
|
tstRslt.MassEndRaw = tstRslt.TargetVolume() * Formulas.RealDensity() / 1000.0f;
|
|
tstRslt.MassEnd = tstRslt.MassEndRaw;
|
|
tstRslt.DensityIn = Formulas.RealDensity();
|
|
tstRslt.DensityLine = Formulas.RealDensity();
|
|
tstRslt.DensityDiv = Formulas.RealDensity();
|
|
tstRslt.MassOfEvapWater = 0;
|
|
tstRslt.Flow = tstRslt.TargetVolume() / tstRslt.TargetTime();
|
|
tstRslt.VolumeCTV = tstRslt.TargetVolume();
|
|
tstRslt.VolumeMaster = tstRslt.TargetVolume();
|
|
tstRslt.ErrorMaster = 0;
|
|
|
|
tstRslt.AmbTempMean = 20.0f;
|
|
tstRslt.AmbPressMean = 1.0f;
|
|
tstRslt.AmbHumiMean = 50.0f;
|
|
|
|
tstRslt.PressUpStart = 1.0f;
|
|
tstRslt.PressDownStart = 1.0f;
|
|
tstRslt.TempUpStart = 20.0f;
|
|
tstRslt.TempDownStart = 20.0f;
|
|
tstRslt.TempDivStart = 20.0f;
|
|
tstRslt.PressUpEnd = 1.0f;
|
|
tstRslt.PressDownEnd = 1.0f;
|
|
tstRslt.TempUpEnd = 20.0f;
|
|
tstRslt.TempDownEnd = 20.0f;
|
|
tstRslt.TempDivEnd = 20.0f;
|
|
tstRslt.PressUpMean = 1.0f;
|
|
tstRslt.PressDownMean = 1.0f;
|
|
tstRslt.TempUpMean = 20.0f;
|
|
tstRslt.TempDownMean = 20.0f;
|
|
tstRslt.TempDivMean = 20.0f;
|
|
tstRslt.PressUpMin = 1.0f;
|
|
tstRslt.PressDownMin = 1.0f;
|
|
tstRslt.TempUpMin = 20.0f;
|
|
tstRslt.TempDownMin = 20.0f;
|
|
tstRslt.TempDivMin = 20.0f;
|
|
tstRslt.PressUpMax = 1.0f;
|
|
tstRslt.PressDownMax = 1.0f;
|
|
tstRslt.TempUpMax = 20.0f;
|
|
tstRslt.TempDownMax = 20.0f;
|
|
tstRslt.TempDivMax = 20.0f;
|
|
tstRslt.ConductMin = Conductivity.Val;
|
|
tstRslt.ConductMax = Conductivity.Val;
|
|
|
|
tstRslt.FlowMean = (float)RefFlowStat.Average;
|
|
tstRslt.FlowStart = (float)RefFlowStat.First;
|
|
tstRslt.FlowEnd = (float)RefFlowStat.Last;
|
|
tstRslt.FlowMin = (float)RefFlowStat.Min;
|
|
tstRslt.FlowMax = (float)RefFlowStat.Max;
|
|
|
|
for (int i = 0; i < BatchRslts.WMPositionsCount; i++)
|
|
{
|
|
Results.Entities.MeterTestRslt compoundRslt = ProcessData.BatchRslts.GetMeterTestRslt(fullTestName, i, CompoundMeterId.Compound);
|
|
Results.Entities.MeterTestRslt mainRslt = ProcessData.BatchRslts.GetMeterTestRslt(fullTestName, i, CompoundMeterId.CompoundMain);
|
|
Results.Entities.MeterTestRslt auxRslt = ProcessData.BatchRslts.GetMeterTestRslt(fullTestName, i, CompoundMeterId.CompoundAux);
|
|
|
|
double compoundVolume = tstRslt.TargetVolume() * (1.0 + 0.01 * errorPct);
|
|
double mainVolume = compoundVolume * mainPart;
|
|
double auxVolume = compoundVolume * (1.0 - mainPart);
|
|
|
|
for (int isAux = 0; isAux <= 1; isAux++) /// 0=main, 1=aux
|
|
{
|
|
GenericDevices.IRegReader regReader = sensPath.RegisterReaders[2 * i + isAux];
|
|
Results.Entities.MeterTestRslt meterRslt = (isAux == 0) ? mainRslt : auxRslt;
|
|
|
|
if (meterRslt != null && regReader != null)
|
|
{
|
|
meterRslt.VolumeMeter = (isAux == 0) ? mainVolume : auxVolume;
|
|
|
|
meterRslt.PulsesMeter = regReader.PulsesPerLtr * meterRslt.VolumeMeter;
|
|
meterRslt.PulsesMaster = tstRslt.PulsesMaster;
|
|
meterRslt.PulsesPerLiter = regReader.PulsesPerLtr;
|
|
meterRslt.VolumeStart = 0;
|
|
meterRslt.VolumeEnd = meterRslt.VolumeMeter;
|
|
meterRslt.VolumeRef = tstRslt.TargetVolume();
|
|
meterRslt.TimestampStart = 0;
|
|
meterRslt.TimestampEnd = tstRslt.TargetTime();
|
|
meterRslt.TestTime = tstRslt.TargetTime();
|
|
meterRslt.Error = Formulas.ErrorFromVolumes(meterRslt.VolumeMeter, tstRslt.VolumeCTV);
|
|
meterRslt.Passed = (errorPct >= tstRslt.ErrLimLo() + tstRslt.ErrLimMargin())
|
|
&& (errorPct <= tstRslt.ErrLimHi() - tstRslt.ErrLimMargin());
|
|
meterRslt.TestDone = true;
|
|
}
|
|
}
|
|
|
|
compoundRslt.VolumeRef = tstRslt.VolumeCTV; /// [l] must be calculated before main & aux. meter error
|
|
compoundRslt.VolumeMeter = mainRslt.VolumeMeter + auxRslt.VolumeMeter;
|
|
|
|
compoundRslt.PulsesMaster = tstRslt.PulsesMaster;
|
|
compoundRslt.TestTime = tstRslt.TargetTime();
|
|
compoundRslt.Error = Formulas.ErrorFromVolumes(compoundRslt.VolumeMeter, tstRslt.VolumeCTV);
|
|
compoundRslt.Passed = (compoundRslt.Error >= tstRslt.ErrLimLo() + tstRslt.ErrLimMargin())
|
|
&& (compoundRslt.Error <= tstRslt.ErrLimHi() - tstRslt.ErrLimMargin());
|
|
compoundRslt.TestDone = true;
|
|
tstRslt.TestDone = true;
|
|
}
|
|
|
|
tstRslt.Components = Results.Entities.Components
|
|
.UpdateList(BatchRslts.ComponentsList,
|
|
new Results.Entities.Components((BenchInfo != null) ? BenchInfo.TestBenchId : 1,
|
|
(BenchInfo != null) ? BenchInfo.TestBenchName : "testbench",
|
|
inPath.Pump != null ? inPath.Pump.Name : string.Empty,
|
|
outPath.FlowMeter != null ? outPath.FlowMeter.Name : string.Empty,
|
|
outPath.Scale != null ? outPath.Scale.Name : string.Empty,
|
|
outPath.RegValve != null ? outPath.RegValve.Name : string.Empty,
|
|
outPath.Diverter != null ? outPath.Diverter.Name : string.Empty));
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Create a simulated test result (heat meters).
|
|
/// </summary>
|
|
/// <param name="test">Test to be simulated</param>
|
|
/// <returns>Test result</returns>
|
|
protected void MakeSimulatedHeatMeters(Config.Entities.Test test, int repetitionNr, int part, float errorPct, double energy, float energyErrLimLo, float energyErrLimHi, bool evaluateVolume)
|
|
{
|
|
string fullTestName = Common.Utils.GetTestName(test.Name, test.Repeats, repetitionNr);
|
|
|
|
Results.Entities.TestRslt tstRslt = ProcessData.BatchRslts.GetTestRslt(fullTestName, part);
|
|
|
|
if (tstRslt == null) return; /// Prevent program crash in certain cases
|
|
|
|
tstRslt.MethodClass = TbfComponents.FindComponent(test.Method).ClassName;
|
|
tstRslt.StartTime = DateTime.Now;
|
|
tstRslt.EndTime = DateTime.Now + new TimeSpan(0, 0, 1);
|
|
tstRslt.FlowSetTime = 10;
|
|
tstRslt.TestTime = tstRslt.TargetTime();
|
|
/// TODO: Verify whether 'ltrPerRefPulse' is up to date
|
|
tstRslt.ConstMasterRaw = outPath.FlowMeter.LtrPerPulse;
|
|
tstRslt.ConstMaster = outPath.FlowMeter.LtrPerPulse;
|
|
tstRslt.PulsesMaster = (tstRslt.ConstMasterRaw > 1E-6) ? (tstRslt.TargetVolume() / tstRslt.ConstMasterRaw) : 1;
|
|
tstRslt.MassStartRaw = 0;
|
|
tstRslt.MassStart = 0;
|
|
tstRslt.MassEndRaw = tstRslt.TargetVolume() * Formulas.RealDensity() / 1000.0f;
|
|
tstRslt.MassEnd = tstRslt.MassEndRaw;
|
|
tstRslt.DensityIn = Formulas.RealDensity();
|
|
tstRslt.DensityLine = Formulas.RealDensity();
|
|
tstRslt.DensityDiv = Formulas.RealDensity();
|
|
tstRslt.MassOfEvapWater = 0;
|
|
tstRslt.Flow = tstRslt.TargetVolume() / tstRslt.TargetTime();
|
|
tstRslt.VolumeCTV = tstRslt.TargetVolume();
|
|
tstRslt.VolumeMaster = tstRslt.TargetVolume();
|
|
tstRslt.ErrorMaster = 0;
|
|
|
|
tstRslt.AmbTempMean = 20.0f;
|
|
tstRslt.AmbPressMean = 1.0f;
|
|
tstRslt.AmbHumiMean = 50.0f;
|
|
|
|
tstRslt.PressUpStart = 1.0f;
|
|
tstRslt.PressDownStart = 1.0f;
|
|
tstRslt.TempUpStart = 20.0f;
|
|
tstRslt.TempDownStart = 20.0f;
|
|
tstRslt.TempDivStart = 20.0f;
|
|
tstRslt.PressUpEnd = 1.0f;
|
|
tstRslt.PressDownEnd = 1.0f;
|
|
tstRslt.TempUpEnd = 20.0f;
|
|
tstRslt.TempDownEnd = 20.0f;
|
|
tstRslt.TempDivEnd = 20.0f;
|
|
tstRslt.PressUpMean = 1.0f;
|
|
tstRslt.PressDownMean = 1.0f;
|
|
tstRslt.TempUpMean = 20.0f;
|
|
tstRslt.TempDownMean = 20.0f;
|
|
tstRslt.TempDivMean = 20.0f;
|
|
tstRslt.PressUpMin = 1.0f;
|
|
tstRslt.PressDownMin = 1.0f;
|
|
tstRslt.TempUpMin = 20.0f;
|
|
tstRslt.TempDownMin = 20.0f;
|
|
tstRslt.TempDivMin = 20.0f;
|
|
tstRslt.PressUpMax = 1.0f;
|
|
tstRslt.PressDownMax = 1.0f;
|
|
tstRslt.TempUpMax = 20.0f;
|
|
tstRslt.TempDownMax = 20.0f;
|
|
tstRslt.TempDivMax = 20.0f;
|
|
tstRslt.ConductMin = Conductivity.Val;
|
|
tstRslt.ConductMax = Conductivity.Val;
|
|
|
|
tstRslt.FlowMean = 0; /// TODO
|
|
tstRslt.FlowMax = 0; /// TODO
|
|
|
|
for (int i = 0; i < BatchRslts.WMPositionsCount; i++)
|
|
{
|
|
Results.Entities.MeterTestRslt energyRslt = ProcessData.BatchRslts.GetMeterTestRslt(fullTestName, i, CompoundMeterId.HeatMeterEnergy);
|
|
Results.Entities.MeterTestRslt volumeRslt = ProcessData.BatchRslts.GetMeterTestRslt(fullTestName, i, CompoundMeterId.HeatMeterVolume);
|
|
|
|
GenericDevices.IRegReader volumeRegReader = (sensPath.RegisterReaders.Length > 2 * i) ? sensPath.RegisterReaders[2 * i] : null;
|
|
GenericDevices.IRegReader energyRegReader = (sensPath.RegisterReaders.Length > 2 * i + 1) ? sensPath.RegisterReaders[2 * i + 1] : null;
|
|
|
|
double volumeMeter = tstRslt.TargetVolume() * (1.0 + 0.01 * errorPct);
|
|
double energyMeter = energy * (1.0 + 0.01 * errorPct);
|
|
|
|
if (volumeRslt != null && volumeRegReader != null)
|
|
{
|
|
volumeRslt.VolumeMeter = volumeMeter;
|
|
|
|
volumeRslt.PulsesMeter = volumeRegReader.PulsesPerLtr * volumeMeter;
|
|
volumeRslt.PulsesMaster = tstRslt.PulsesMaster;
|
|
volumeRslt.PulsesPerLiter = volumeRegReader.PulsesPerLtr;
|
|
volumeRslt.VolumeStart = 0;
|
|
volumeRslt.VolumeEnd = volumeMeter;
|
|
volumeRslt.VolumeRef = tstRslt.TargetVolume();
|
|
volumeRslt.TimestampStart = 0;
|
|
volumeRslt.TimestampEnd = tstRslt.TargetTime();
|
|
volumeRslt.TestTime = tstRslt.TargetTime();
|
|
volumeRslt.Error = Formulas.ErrorFromVolumes(volumeMeter, tstRslt.VolumeCTV);
|
|
volumeRslt.Passed = !evaluateVolume ||
|
|
((errorPct >= tstRslt.ErrLimLo() + tstRslt.ErrLimMargin()) &&
|
|
(errorPct <= tstRslt.ErrLimHi() - tstRslt.ErrLimMargin()));
|
|
volumeRslt.TestDone = true;
|
|
tstRslt.TestDone = true;
|
|
}
|
|
|
|
if (energyRslt != null && energyRegReader != null)
|
|
{
|
|
energyRslt.VolumeMeter = energyMeter;
|
|
|
|
energyRslt.PulsesMeter = energyRegReader.PulsesPerLtr * energyMeter;
|
|
energyRslt.PulsesMaster = tstRslt.PulsesMaster;
|
|
energyRslt.PulsesPerLiter = energyRegReader.PulsesPerLtr;
|
|
energyRslt.VolumeStart = 0;
|
|
energyRslt.VolumeEnd = energyMeter;
|
|
energyRslt.VolumeRef = energy;
|
|
energyRslt.TimestampStart = 0;
|
|
energyRslt.TimestampEnd = tstRslt.TargetTime();
|
|
energyRslt.TestTime = tstRslt.TargetTime();
|
|
energyRslt.Error = Formulas.ErrorFromVolumes(energyMeter, energy);
|
|
energyRslt.Passed = (errorPct >= energyErrLimLo) && (errorPct <= energyErrLimHi);
|
|
energyRslt.TestDone = true;
|
|
tstRslt.TestDone = true;
|
|
}
|
|
}
|
|
|
|
tstRslt.Components = Results.Entities.Components
|
|
.UpdateList(BatchRslts.ComponentsList,
|
|
new Results.Entities.Components((BenchInfo != null) ? BenchInfo.TestBenchId : 1,
|
|
(BenchInfo != null) ? BenchInfo.TestBenchName : "testbench",
|
|
inPath.Pump != null ? inPath.Pump.Name : string.Empty,
|
|
outPath.FlowMeter != null ? outPath.FlowMeter.Name : string.Empty,
|
|
outPath.Scale != null ? outPath.Scale.Name : string.Empty,
|
|
outPath.RegValve != null ? outPath.RegValve.Name : string.Empty,
|
|
outPath.Diverter != null ? outPath.Diverter.Name : string.Empty));
|
|
}
|
|
|
|
protected bool TestAndLogUiCmdStop(IList<Event> e)
|
|
{
|
|
return TestAndLogUiCmdStop(null, e);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns true and makes a log when 'e' contains Event.UiCmdStop
|
|
/// </summary>
|
|
/// <param name="test">test or null (only for logs)</param>
|
|
/// <param name="e"></param>
|
|
/// <returns></returns>
|
|
protected bool TestAndLogUiCmdStop(Test test, IList<Event> e)
|
|
{
|
|
if (!e.Contains(Event.UiCmdStop)) return false;
|
|
|
|
log.FatalFormat("STOP pressed: Procedure={0}, Test={1}, State={2}",
|
|
(StateMachine.Procedure == null) ? "?" : StateMachine.Procedure.Name,
|
|
(test == null) ? "?" : test.Name,
|
|
State.CurrentState.Name);
|
|
|
|
if (test != null)
|
|
{
|
|
log.FatalFormat("Process values:");
|
|
log.FatalFormat(" Method: {0}", test.Method);
|
|
log.FatalFormat(" Test start time: {0}", TestStartTime.ToShortTimeString());
|
|
log.FatalFormat(" Feeding path: {0}", (inPath != null) ? inPath.ToString() : "none");
|
|
log.FatalFormat(" Bench path: {0}", (benchPath != null) ? benchPath.ToString() : "none");
|
|
log.FatalFormat(" Output path: {0}", (outPath != null) ? outPath.ToString() : "none");
|
|
if (inPath.Pump is IPump) log.FatalFormat(" Pump power: {0}%", (inPath.Pump as IPump).Power);
|
|
else if (inPath.Pump is IValve) log.FatalFormat(" Feeding valve: {0}", (inPath.Pump as IValve).State ? "open" : "close");
|
|
if (outPath.RegValve is IRegValve) log.FatalFormat(" Regulation valve position: {0}%", outPath.RegValve.Position);
|
|
log.FatalFormat(" Flow: {0}", RefFlow);
|
|
log.FatalFormat(" Mass: {0}", (outPath.Scale is IScale) ? (outPath.Scale as IScale).Mass : 0);
|
|
log.FatalFormat(" Start mass: {0}", StartMass);
|
|
log.FatalFormat(" Reference pulses: {0}", RefPulses);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
}
|
|
}
|