tbf/TBF/Rig/Sequences/SequenceBase.cs
Marek Frniak 37c89a4c9c Fix - missing safe shutdown when PerformSteps returns UiCmdStop
- 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.
2026-07-14 14:41:53 +02:00

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;
}
}
}