Changes in MainSeq and StateMachine : AutoActions invocation.
This commit is contained in:
parent
b1d692230e
commit
a20c9eb2bd
@ -6,20 +6,17 @@ using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using log4net;
|
||||
using NHibernate;
|
||||
using Config;
|
||||
using Config.Entities;
|
||||
using Results.Entities;
|
||||
using TBF.UiBridge;
|
||||
using TBF.BenchControl.Operations;
|
||||
using TBF.BenchControl.GenericDevices;
|
||||
using TBF.Boxes;
|
||||
using TBF.Resources;
|
||||
using System.Threading;
|
||||
using System.IO;
|
||||
using TBF.UiBridge;
|
||||
|
||||
namespace TBF.BenchControl.Sequences
|
||||
{
|
||||
public class MainSeq : SequenceBase
|
||||
public partial class MainSeq : SequenceBase
|
||||
{
|
||||
private static readonly ILog log = LogManager.GetLogger(typeof(MainSeq));
|
||||
|
||||
@ -79,7 +76,9 @@ namespace TBF.BenchControl.Sequences
|
||||
|
||||
|
||||
|
||||
/// <summary> Constructor </summary>
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
public MainSeq()
|
||||
{
|
||||
benchFilled = false;
|
||||
@ -99,268 +98,8 @@ namespace TBF.BenchControl.Sequences
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Unconditionally wait for OK button
|
||||
/// Main sequence execution
|
||||
/// </summary>
|
||||
void WaitForOkButton()
|
||||
{
|
||||
State.Create("MainSeq : Press OK to start the system")
|
||||
.AddOperation(new BenchControl.Operations.MessageBoxOp(Strings.Start_the_test_bench, System.Drawing.Color.OliveDrab))
|
||||
.EnterState();
|
||||
|
||||
while (!StateMachine.WaitRunDevsRunOps().Contains(Event.OK)) { }
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Unconditionally set valves to default position
|
||||
/// </summary>
|
||||
void SetValvesToDefaultState()
|
||||
{
|
||||
State.Create("MainSeq : Setting valves to default positions")
|
||||
.AddOperation(StateMachine.ControlBoard.SetValvesOp(StateMachine.DefaultValvesOpen, StateMachine.DefaultValvesClose))
|
||||
.EnterState();
|
||||
|
||||
while (StateMachine.WaitRunDevsRunOps().Contains(Event.ValvesBusy)) { }
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Test communication with all scales that support S/N read operation
|
||||
/// </summary>
|
||||
/// <param name="scaleName">Name of a scale that failed</param>
|
||||
/// <param name="message">Message in case of a failure</param>
|
||||
/// <returns>true = Test passed, all scales communicate OK</returns>
|
||||
bool TestCommunicationWithScales(out string scaleName, out string message)
|
||||
{
|
||||
///
|
||||
/// Read S/N-s from scales (cannot be stopped, but is limitted to Scales count x 3s (=timeout)
|
||||
///
|
||||
IScaleOrTank[] tanks = new IScaleOrTank[] { StateMachine.Tank1, StateMachine.Tank2, StateMachine.Tank3 };
|
||||
|
||||
foreach (var tank in tanks)
|
||||
{
|
||||
if (tank is IScale)
|
||||
{
|
||||
IScale scale = tank as IScale;
|
||||
string sn = string.Empty;
|
||||
IOperation getSNOp = scale.GetSerNumOp(ref sn);
|
||||
|
||||
if (getSNOp != null)
|
||||
{
|
||||
const int nrRetries = 3;
|
||||
|
||||
for (int i = 1; i <= nrRetries; i++)
|
||||
{
|
||||
IList<Event> e;
|
||||
bool error = false;
|
||||
bool timeout = false;
|
||||
|
||||
State.Create(string.Format("MainSeq : Reading S/N of scale {0} trial {1}", scale.Name, i))
|
||||
.AddOperation(getSNOp)
|
||||
.AddOperation(new Operations.TimerOp(2))
|
||||
.EnterState();
|
||||
do
|
||||
{
|
||||
e = StateMachine.WaitRunDevsRunOps();
|
||||
if (e.Contains(Event.Error))
|
||||
{
|
||||
if (i == nrRetries)
|
||||
{
|
||||
///
|
||||
/// All retries completed => the scale failed
|
||||
///
|
||||
scaleName = scale.Name;
|
||||
message = Strings.Scale_communication_error;
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
/// The scale failed => try one more time
|
||||
error = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (e.Contains(Event.Busy) && e.Contains(Event.TimerExpired))
|
||||
{
|
||||
if (i == nrRetries)
|
||||
{
|
||||
///
|
||||
/// All retries completed, the scale failed
|
||||
///
|
||||
scaleName = scale.Name;
|
||||
message = Strings.Scale_communication_timeout;
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
/// The scale failed => try one more time
|
||||
timeout = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
while (e.Contains(Event.Busy));
|
||||
|
||||
if (!error && !timeout)
|
||||
{
|
||||
/// This scale communicates OK, break "for (int i = ... " loop
|
||||
if (!string.IsNullOrEmpty(sn)) log.WarnFormat("Scale {0} : s/n = {1}", scale.Name, sn);
|
||||
break; ///
|
||||
}
|
||||
|
||||
/// Wait one state machine tick (1 second), kreep retrying, stay inside "for (int i = ... " loop
|
||||
State.Create(string.Format("MainSeq : Reading S/N of scale {0}", scale.Name)).EnterState();
|
||||
StateMachine.WaitRunDevsRunOps();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
/// All scales communicate OK, test passed
|
||||
///
|
||||
scaleName = string.Empty;
|
||||
message = string.Empty;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <returns>true = OK, false = error</returns>
|
||||
bool DrainTanks()
|
||||
{
|
||||
IList<Event> e;
|
||||
|
||||
///
|
||||
/// Enable stop draining buttons
|
||||
///
|
||||
Bridge.Bench2UI(((StateMachine.DrainValve1 != null) ? ButtonsEtc.DrainTankBtn1Hi : 0) |
|
||||
((StateMachine.DrainValve2 != null) ? ButtonsEtc.DrainTankBtn2Hi : 0) |
|
||||
((StateMachine.DrainValve3 != null) ? ButtonsEtc.DrainTankBtn3Hi : 0));
|
||||
|
||||
///
|
||||
/// Determine lists of drain valves and drain times (max. of all tank drain times)
|
||||
///
|
||||
IList<IValve> fullDrainValves = new List<IValve>();
|
||||
IList<IValve> secondHalfDrainValves = new List<IValve>();
|
||||
IList<IValve> allDrainValves = new List<IValve>();
|
||||
int totalDrainTime = 0;
|
||||
int maxDrainTimeFor2VlvTanks = 0;
|
||||
bool areTwoDrainPhases = false;
|
||||
foreach (IScaleOrTank tank in new IScaleOrTank[] { StateMachine.Tank1, StateMachine.Tank2, StateMachine.Tank3 })
|
||||
{
|
||||
if (tank != null && tank.DrainValve != null)
|
||||
{
|
||||
if (tank.EmptyTimeSec > totalDrainTime) totalDrainTime = tank.EmptyTimeSec;
|
||||
if (tank.DrainValve2 != null)
|
||||
{
|
||||
areTwoDrainPhases = true;
|
||||
if (tank.EmptyTimeSec > maxDrainTimeFor2VlvTanks) maxDrainTimeFor2VlvTanks = tank.EmptyTimeSec;
|
||||
|
||||
if (!secondHalfDrainValves.Contains(tank.DrainValve)) secondHalfDrainValves.Add(tank.DrainValve);
|
||||
if (!fullDrainValves.Contains(tank.DrainValve2)) fullDrainValves.Add(tank.DrainValve2);
|
||||
if (!allDrainValves.Contains(tank.DrainValve)) allDrainValves.Add(tank.DrainValve);
|
||||
if (!allDrainValves.Contains(tank.DrainValve2)) allDrainValves.Add(tank.DrainValve2);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!fullDrainValves.Contains(tank.DrainValve)) fullDrainValves.Add(tank.DrainValve);
|
||||
if (!allDrainValves.Contains(tank.DrainValve)) allDrainValves.Add(tank.DrainValve);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
/// Drain the tanks, two phases if necessary
|
||||
///
|
||||
if (totalDrainTime > 0)
|
||||
{
|
||||
IntBox timerTime = new IntBox(); /// Contains remaining time in each phase
|
||||
int firstPhaseTime = maxDrainTimeFor2VlvTanks / 2;
|
||||
|
||||
State.Create(areTwoDrainPhases ? "MainSeq : Drain tanks - phase 1" : "MainSeq : Drain tanks")
|
||||
.AddOperation(checkUiOp)
|
||||
.AddOperation(new TimerOp(areTwoDrainPhases ? firstPhaseTime : totalDrainTime, timerTime))
|
||||
.AddOperation(StateMachine.ControlBoard.SetValvesOp(fullDrainValves, null))
|
||||
.EnterState();
|
||||
do {
|
||||
int remTime = areTwoDrainPhases ? (timerTime.Val + totalDrainTime - firstPhaseTime) : timerTime.Val;
|
||||
Bridge.OnActivity(this, string.Format("{0} ... {1} {2} {3} {4}", Strings.Emptying_tank, remTime / 60, "min", remTime % 60, Strings.sec));
|
||||
|
||||
e = StateMachine.WaitRunDevsRunOps();
|
||||
if (e.Contains(Event.Error)) return false;
|
||||
bool stopDrainingCmd = e.Contains(Event.UiCmdStopDrainingTank1) || e.Contains(Event.UiCmdStopDrainingTank2) || e.Contains(Event.UiCmdStopDrainingTank3);
|
||||
if (stopDrainingCmd && !e.Contains(Event.ValvesBusy) && !e.Contains(Event.CameraBusy)) break;
|
||||
}
|
||||
while (e.Contains(Event.TimerBusy) || e.Contains(Event.CameraBusy) || e.Contains(Event.ValvesBusy));
|
||||
|
||||
if (areTwoDrainPhases)
|
||||
{
|
||||
State.Create("MainSeq : Drain tanks - phase 2")
|
||||
.AddOperation(checkUiOp)
|
||||
.AddOperation(new TimerOp(totalDrainTime - firstPhaseTime, timerTime))
|
||||
.AddOperation(StateMachine.ControlBoard.SetValvesOp(secondHalfDrainValves, null))
|
||||
.EnterState();
|
||||
do {
|
||||
int remTime = timerTime.Val;
|
||||
Bridge.OnActivity(this, string.Format("{0} ... {1} {2} {3} {4}", Strings.Emptying_tank, remTime / 60, "min", remTime % 60, Strings.sec));
|
||||
|
||||
e = StateMachine.WaitRunDevsRunOps();
|
||||
if (e.Contains(Event.Error)) return false;
|
||||
bool stopDrainingCmd = e.Contains(Event.UiCmdStopDrainingTank1) || e.Contains(Event.UiCmdStopDrainingTank2) || e.Contains(Event.UiCmdStopDrainingTank3);
|
||||
if (stopDrainingCmd && !e.Contains(Event.ValvesBusy) && !e.Contains(Event.CameraBusy)) break;
|
||||
}
|
||||
while (e.Contains(Event.TimerBusy) || e.Contains(Event.CameraBusy) || e.Contains(Event.ValvesBusy));
|
||||
}
|
||||
|
||||
Bridge.OnActivity(this, Strings.Emptying_tank);
|
||||
|
||||
State stopDraining = State.Create("MainSeq : Stop draining water tanks")
|
||||
.AddOperation(checkUiOp)
|
||||
.AddOperation(StateMachine.ControlBoard.SetValvesOp(null, allDrainValves))
|
||||
.EnterState();
|
||||
do {
|
||||
e = StateMachine.WaitRunDevsRunOps();
|
||||
if (e.Contains(Event.Error)) return false;
|
||||
}
|
||||
while (e.Contains(Event.ValvesBusy));
|
||||
}
|
||||
|
||||
return true; /// OK
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// This function is called after a procedure was selected and all components procedure parameters of components were loaded
|
||||
/// </summary>
|
||||
void ClearSessionData()
|
||||
{
|
||||
///
|
||||
/// Clear iperlhead data (including PCB Number, avoid double use)
|
||||
///
|
||||
foreach (var cmpnt in StateMachine.Components)
|
||||
{
|
||||
if (cmpnt is TestMethods.iPerlCommunication.iPerlHead.IperlHead)
|
||||
{
|
||||
(cmpnt as TestMethods.iPerlCommunication.iPerlHead.IperlHead).ClearData();
|
||||
}
|
||||
}
|
||||
|
||||
IsQ2PreCorrectionCalculated = false;
|
||||
CalculatedQ2PreCorrectionLR = 0;
|
||||
CalculatedQ2PreCorrectionRL = 0;
|
||||
RawTestInfos = null;
|
||||
CompleteTestInfos = null;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Main sequence
|
||||
/// </summary>
|
||||
/// <param name="dummyArg"></param>
|
||||
/// <returns></returns>
|
||||
public void Execute()
|
||||
{
|
||||
IList<Event> e = new List<Event>();
|
||||
@ -446,10 +185,17 @@ namespace TBF.BenchControl.Sequences
|
||||
: ((selection == Selection.Q2) ? "Q2"
|
||||
: ((selection == Selection.Q3) ? "Q3" : Bridge.SelectedTestName));
|
||||
|
||||
///
|
||||
/// Auto invocation actions
|
||||
///
|
||||
IList<string> procedureBefore = new List<string>();
|
||||
IList<string> testsInside = new List<string>();
|
||||
IList<string> procedureAfer = new List<string>();
|
||||
|
||||
///
|
||||
/// Collect information about the interrupted procedure (if applicable)
|
||||
///
|
||||
bool restoreInterruptedSession = false;
|
||||
bool processDataHeaderOK = false;
|
||||
string interruptedProcedureName = string.Empty;
|
||||
bool isRemoteIntProc = false;
|
||||
@ -477,6 +223,8 @@ namespace TBF.BenchControl.Sequences
|
||||
UiBridge.Bridge.OnError(this, Strings.Invalid_batch_number);
|
||||
continue;
|
||||
}
|
||||
|
||||
restoreInterruptedSession = true;
|
||||
}
|
||||
|
||||
|
||||
@ -490,8 +238,10 @@ namespace TBF.BenchControl.Sequences
|
||||
///
|
||||
/// Try to load all parameters of selected or restored procedure from the respective database
|
||||
///
|
||||
if (processDataHeaderOK)
|
||||
if (restoreInterruptedSession)
|
||||
{
|
||||
/// User has chosen to restore an interrupted session and necessary conditions are met
|
||||
|
||||
/// TODO: Repeate twice for Users.Entities.DBKind.Config and Users.Entities.DBKind.RemoteConfig
|
||||
using (ISession remoteOrLocalSession = Config.FluentCommon.CreateSession(isRemoteIntProc ?
|
||||
Users.Entities.DBKind.RemoteConfig :
|
||||
@ -500,22 +250,37 @@ namespace TBF.BenchControl.Sequences
|
||||
StateMachine.LoadProcedure(remoteOrLocalSession, interruptedProcedureName, isRemoteIntProc);
|
||||
StateMachine.LoadProcedureParams(StateMachine.Procedure);
|
||||
|
||||
/// This is to load Procedure.Tests and tets.MoreParams for each test
|
||||
/// This is to load Procedure.Tests and test.MoreParams for each test
|
||||
int a = 0;
|
||||
foreach (var test in StateMachine.Procedure.Tests) a += test.MoreParams.Count;
|
||||
}
|
||||
}
|
||||
else if ((Bridge.SelectedProcedure != null) && !string.IsNullOrEmpty(Bridge.SelectedProcedure.Name))
|
||||
{
|
||||
if (selection == Selection.Cycle)
|
||||
{
|
||||
/// This is a regular complete cycle => check AutoAction==InvokeXY calendar events
|
||||
procedureBefore = ServeCalendarEventsInvokeXY(Config.CalendarEvent.AutoAction.InvokeBeforeCycle, 1);
|
||||
|
||||
if (procedureBefore.Count == 1)
|
||||
{
|
||||
/// TODO: Invoke procedure before a cycle
|
||||
}
|
||||
else
|
||||
{
|
||||
testsInside = ServeCalendarEventsInvokeXY(Config.CalendarEvent.AutoAction.InvokeInsideCycle);
|
||||
}
|
||||
}
|
||||
|
||||
/// TODO: Repeate twice for Users.Entities.DBKind.Config and Users.Entities.DBKind.RemoteConfig
|
||||
using (ISession remoteOrLocalSession = Config.FluentCommon.CreateSession(Bridge.SelectedProcedure.IsRemote ?
|
||||
Users.Entities.DBKind.RemoteConfig :
|
||||
Users.Entities.DBKind.Config))
|
||||
{
|
||||
StateMachine.LoadProcedure(remoteOrLocalSession, Bridge.SelectedProcedure.Name, Bridge.SelectedProcedure.IsRemote);
|
||||
StateMachine.LoadProcedure(remoteOrLocalSession, Bridge.SelectedProcedure.Name, Bridge.SelectedProcedure.IsRemote, testsInside);
|
||||
StateMachine.LoadProcedureParams(StateMachine.Procedure);
|
||||
|
||||
/// This is to load Procedure.Tests and tets.MoreParams for each test
|
||||
/// This is to load Procedure.Tests and test.MoreParams for each test
|
||||
int a = 0;
|
||||
foreach (var test in StateMachine.Procedure.Tests) a += test.MoreParams.Count;
|
||||
}
|
||||
@ -1651,565 +1416,5 @@ namespace TBF.BenchControl.Sequences
|
||||
Shutdown,
|
||||
RestoreInterruptedSession,
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Idle loop to make a procedure or test selection.
|
||||
/// Handles tank emptying, camera test.
|
||||
/// </summary>
|
||||
/// <param name="context">Context where MakeSelection() is called</param>
|
||||
/// <returns>
|
||||
/// Selection.PurgeBegin, PurgeEnd, Break, Cycle, Test, Q1, Q2, Q3 or SaveResults
|
||||
/// </returns>
|
||||
Selection MakeSelection(MKSelContext context)
|
||||
{
|
||||
log.WarnFormat("MakeSelection({0})", context);
|
||||
|
||||
bool restoreIntrptdSessionEnabled = (context == MKSelContext.ProcedureNotSelected) && File.Exists(ProcessData.PDataFileName);
|
||||
|
||||
/// Tank emptying valves states
|
||||
bool draining1 = false;
|
||||
bool draining2 = false;
|
||||
bool draining3 = false;
|
||||
|
||||
/// Measured masses to control emptying
|
||||
DoubleBox mass1 = new DoubleBox();
|
||||
DoubleBox mass2 = new DoubleBox();
|
||||
DoubleBox mass3 = new DoubleBox();
|
||||
|
||||
IList<Event> e;
|
||||
|
||||
while (true)
|
||||
{
|
||||
bool draining = draining1 || draining2 || draining3;
|
||||
|
||||
///
|
||||
/// Activity message
|
||||
///
|
||||
Bridge.OnActivity(this, draining ? Strings.Emptying_tank
|
||||
: ((context == MKSelContext.ProcedureNotSelected) ? Strings.Please_select_a_procedure
|
||||
: Strings.Please_select_a_cycle_a_test_or_empty));
|
||||
|
||||
bool saveResultsActive = (context == MKSelContext.InsideProcedure)
|
||||
&& (StateMachine.Procedure != null)
|
||||
&& (!StateMachine.Procedure.MustBeComplete || BatchRslts.AllTestsDone());
|
||||
|
||||
/// Enable appropriate UI controls and buttons
|
||||
Bridge.Bench2UI(((context == MKSelContext.ProcedureNotSelected) ? ButtonsEtc.ProcedureCmbBoxEn : 0) |
|
||||
ButtonsEtc.TestCmbBoxEn |
|
||||
((context == MKSelContext.InsideProcedure) ? ButtonsEtc.Break : 0) |
|
||||
(restoreIntrptdSessionEnabled ? ButtonsEtc.RestoreSession : 0) |
|
||||
(saveResultsActive ? ButtonsEtc.AcceptResultsBtnEn : 0) |
|
||||
(draining ? 0 : ButtonsEtc.StartCycleBtnEn) |
|
||||
(draining ? 0 : ButtonsEtc.StartTestBtnsEn) |
|
||||
(draining ? 0 : ButtonsEtc.PurgeBeginBtnEn) |
|
||||
(draining ? 0 : ((context == MKSelContext.InsideProcedure) ? ButtonsEtc.PurgeEndBtnEn : 0)) |
|
||||
((StateMachine.DrainValve1 == null) ? 0 : (draining1 ? ButtonsEtc.DrainTankBtn1Hi : ButtonsEtc.DrainTankBtn1En)) |
|
||||
((StateMachine.DrainValve2 == null) ? 0 : (draining2 ? ButtonsEtc.DrainTankBtn2Hi : ButtonsEtc.DrainTankBtn2En)) |
|
||||
((StateMachine.DrainValve3 == null) ? 0 : (draining3 ? ButtonsEtc.DrainTankBtn3Hi : ButtonsEtc.DrainTankBtn3En)));
|
||||
|
||||
|
||||
State.Create("MainSeq : Select an activity")
|
||||
.AddOperation(checkUiOp)
|
||||
.AddOperation(StateMachine.BenchWaitingOp)
|
||||
.AddOperation((StateMachine.Tank1 is IScale) ? (StateMachine.Tank1 as IScale).ReadMassOp(ref mass1) : null)
|
||||
.AddOperation((StateMachine.Tank2 is IScale) ? (StateMachine.Tank2 as IScale).ReadMassOp(ref mass2) : null)
|
||||
.AddOperation((StateMachine.Tank3 is IScale) ? (StateMachine.Tank3 as IScale).ReadMassOp(ref mass3) : null)
|
||||
.EnterState();
|
||||
do
|
||||
{
|
||||
e = StateMachine.WaitRunDevsRunOps();
|
||||
|
||||
/// Handled inside MakeSelection() inside the selection loop
|
||||
if (e.Contains(Event.Error)) break;
|
||||
if (!draining1 && e.Contains(Event.UiCmdDrainTank1)) break;
|
||||
if (!draining2 && e.Contains(Event.UiCmdDrainTank2)) break;
|
||||
if (!draining3 && e.Contains(Event.UiCmdDrainTank3)) break;
|
||||
if (draining1 && e.Contains(Event.UiCmdStopDrainingTank1)) break;
|
||||
if (draining2 && e.Contains(Event.UiCmdStopDrainingTank2)) break;
|
||||
if (draining3 && e.Contains(Event.UiCmdStopDrainingTank3)) break;
|
||||
if (draining1 && StateMachine.Tank1.IsEmpty()) break;
|
||||
if (draining2 && StateMachine.Tank2.IsEmpty()) break;
|
||||
if (draining3 && StateMachine.Tank3.IsEmpty()) break;
|
||||
|
||||
/// Quit the selection loop and leave MakeSelection()
|
||||
if (e.Contains(Event.UiCmdShutdown)) return Selection.Shutdown;
|
||||
if (context == MKSelContext.InsideProcedure
|
||||
&& e.Contains(Event.UiCmdBreak)) return Selection.Break;
|
||||
if (e.Contains(Event.UiCmdPurgeBegin)) return Selection.PurgeBegin;
|
||||
if (e.Contains(Event.UiCmdPurgeEnd)) return Selection.PurgeEnd;
|
||||
if (e.Contains(Event.UiCmdStartCycle)) return Selection.Cycle;
|
||||
if (e.Contains(Event.UiCmdStartTest)) return Selection.Test;
|
||||
if (e.Contains(Event.UiCmdStartQ1)) return Selection.Q1;
|
||||
if (e.Contains(Event.UiCmdStartQ2)) return Selection.Q2;
|
||||
if (e.Contains(Event.UiCmdStartQ3)) return Selection.Q3;
|
||||
if (e.Contains(Event.UiCmdAcceptResults)) return Selection.SaveResults;
|
||||
if (e.Contains(Event.UiCmdReloadBatch)) return Selection.RestoreBatch;
|
||||
if (e.Contains(Event.UiCmdReloadAndFixBatch)) return Selection.RestoreAndFixBatch;
|
||||
if (restoreIntrptdSessionEnabled
|
||||
&& e.Contains(Event.UiCmdRestoreSession)) return Selection.RestoreInterruptedSession;
|
||||
}
|
||||
while (true);
|
||||
|
||||
|
||||
if (e.Contains(Event.Error))
|
||||
{
|
||||
///------------------------------------
|
||||
Bridge.OnActivity(this, Strings.Error);
|
||||
///------------------------------------
|
||||
State.Create("MainSeq : ERROR state")
|
||||
.AddOperation(checkUiOp)
|
||||
.AddOperation(StateMachine.BenchErrorOp)
|
||||
.EnterState();
|
||||
do
|
||||
{
|
||||
e = StateMachine.WaitRunDevsRunOps();
|
||||
}
|
||||
while (!e.Contains(Event.UiCmdShutdown));
|
||||
|
||||
return Selection.Shutdown;
|
||||
}
|
||||
else
|
||||
{
|
||||
string stateText = "MainSeq : ";
|
||||
IList<IValve> openValves = new List<IValve>();
|
||||
IList<IValve> closeValves = new List<IValve>();
|
||||
|
||||
if (draining1 && (StateMachine.Tank1.IsEmpty() || e.Contains(Event.UiCmdStopDrainingTank1)))
|
||||
{
|
||||
draining1 = false;
|
||||
closeValves.Add(StateMachine.DrainValve1);
|
||||
stateText = stateText + "close tank 1, ";
|
||||
}
|
||||
else if (draining2 && (StateMachine.Tank2.IsEmpty() || e.Contains(Event.UiCmdStopDrainingTank2)))
|
||||
{
|
||||
draining2 = false;
|
||||
closeValves.Add(StateMachine.DrainValve2);
|
||||
stateText = stateText + "close tank 2, ";
|
||||
}
|
||||
else if (draining3 && (StateMachine.Tank3.IsEmpty() || e.Contains(Event.UiCmdStopDrainingTank3)))
|
||||
{
|
||||
draining3 = false;
|
||||
closeValves.Add(StateMachine.DrainValve3);
|
||||
stateText = stateText + "close tank 3, ";
|
||||
}
|
||||
else if (!draining1 && e.Contains(Event.UiCmdDrainTank1))
|
||||
{
|
||||
draining1 = true;
|
||||
openValves.Add(StateMachine.DrainValve1);
|
||||
stateText = stateText + "open tank 1, ";
|
||||
}
|
||||
else if (!draining2 && e.Contains(Event.UiCmdDrainTank2))
|
||||
{
|
||||
draining2 = true;
|
||||
openValves.Add(StateMachine.DrainValve2);
|
||||
stateText = stateText + "open tank 2, ";
|
||||
}
|
||||
else if (!draining3 && e.Contains(Event.UiCmdDrainTank3))
|
||||
{
|
||||
draining3 = true;
|
||||
openValves.Add(StateMachine.DrainValve3);
|
||||
stateText = stateText + "open tank 3, ";
|
||||
}
|
||||
|
||||
draining = draining1 || draining2 || draining3;
|
||||
if (draining) Bridge.OnActivity(this, Strings.Emptying_tank);
|
||||
|
||||
Bridge.Bench2UI(((context == MKSelContext.ProcedureNotSelected) ? ButtonsEtc.ProcedureCmbBoxEn : 0) |
|
||||
((StateMachine.DrainValve1 == null) ? 0 : (draining1 ? ButtonsEtc.DrainTankBtn1Hi : ButtonsEtc.DrainTankBtn1En)) |
|
||||
((StateMachine.DrainValve2 == null) ? 0 : (draining2 ? ButtonsEtc.DrainTankBtn2Hi : ButtonsEtc.DrainTankBtn2En)) |
|
||||
((StateMachine.DrainValve3 == null) ? 0 : (draining3 ? ButtonsEtc.DrainTankBtn3Hi : ButtonsEtc.DrainTankBtn3En)));
|
||||
|
||||
State.Create(stateText)
|
||||
.AddOperation(StateMachine.ControlBoard.SetValvesOp(openValves, closeValves))
|
||||
.EnterState();
|
||||
do
|
||||
{
|
||||
e = StateMachine.WaitRunDevsRunOps();
|
||||
}
|
||||
while (e.Contains(Event.ValvesBusy));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Shutdown(bool skipTankDraining = false)
|
||||
{
|
||||
log.WarnFormat(string.Format("Shutdown(skipTankDraining={0})", skipTankDraining));
|
||||
|
||||
StateMachine.MachineState = MachineState.ShuttingDown; /// TBF shut down cannot be aborted from now on
|
||||
Bridge.Bench2UI(0); /// All buttons off
|
||||
|
||||
if (!skipTankDraining)
|
||||
{
|
||||
/// Drain time
|
||||
int maxDrainTime = 0;
|
||||
if ((StateMachine.Tank1 != null) && (StateMachine.Tank1.EmptyTimeSec > maxDrainTime)) maxDrainTime = StateMachine.Tank1.EmptyTimeSec;
|
||||
if ((StateMachine.Tank2 != null) && (StateMachine.Tank2.EmptyTimeSec > maxDrainTime)) maxDrainTime = StateMachine.Tank2.EmptyTimeSec;
|
||||
if ((StateMachine.Tank3 != null) && (StateMachine.Tank3.EmptyTimeSec > maxDrainTime)) maxDrainTime = StateMachine.Tank3.EmptyTimeSec;
|
||||
|
||||
/// Drain valves
|
||||
IList<IValve> drainValves = new List<IValve>();
|
||||
if (StateMachine.DrainValve1 != null) drainValves.Add(StateMachine.DrainValve1);
|
||||
if (StateMachine.DrainValve2 != null) drainValves.Add(StateMachine.DrainValve2);
|
||||
if (StateMachine.DrainValve3 != null) drainValves.Add(StateMachine.DrainValve3);
|
||||
|
||||
/// Open all drain valves
|
||||
if (drainValves.Count > 0)
|
||||
{
|
||||
Bridge.OnActivity(this, Strings.Emptying_tank); /// Activity message
|
||||
|
||||
State.Create("Open all drain valves")
|
||||
.AddOperation(StateMachine.ControlBoard.SetValvesOp(drainValves, null))
|
||||
.EnterState();
|
||||
while (StateMachine.WaitRunDevsRunOps().Contains(Event.ValvesBusy)) { }
|
||||
}
|
||||
|
||||
/// Tank emptying valves states
|
||||
bool draining1 = (StateMachine.DrainValve1 != null);
|
||||
bool draining2 = (StateMachine.DrainValve2 != null);
|
||||
bool draining3 = (StateMachine.DrainValve3 != null);
|
||||
|
||||
int drainingStartTime = StateMachine.Time;
|
||||
|
||||
/// Quit the following loop when time expires or all tanks are empty
|
||||
while ((StateMachine.Time < drainingStartTime + maxDrainTime) && (draining1 || draining2 || draining3))
|
||||
{
|
||||
int remTime = drainingStartTime + maxDrainTime - StateMachine.Time;
|
||||
Bridge.OnActivity(this, string.Format("{0} ... {1} {2} {3} {4}", Strings.Emptying_tank, remTime / 60, "min", remTime % 60, Strings.sec));
|
||||
|
||||
DoubleBox mass1 = new DoubleBox();
|
||||
DoubleBox mass2 = new DoubleBox();
|
||||
DoubleBox mass3 = new DoubleBox();
|
||||
///
|
||||
State.Create("MainSeq : Reading mass")
|
||||
.AddOperation(checkUiOp)
|
||||
.AddOperation((StateMachine.Tank1 is IScale) ? (StateMachine.Tank1 as IScale).ReadMassOp(ref mass1) : null)
|
||||
.AddOperation((StateMachine.Tank2 is IScale) ? (StateMachine.Tank2 as IScale).ReadMassOp(ref mass2) : null)
|
||||
.AddOperation((StateMachine.Tank3 is IScale) ? (StateMachine.Tank3 as IScale).ReadMassOp(ref mass3) : null)
|
||||
.EnterState();
|
||||
while (StateMachine.WaitRunDevsRunOps().Contains(Event.Busy)) { }
|
||||
|
||||
if (draining1 && StateMachine.Tank1.IsEmpty()) draining1 = false;
|
||||
if (draining2 && StateMachine.Tank2.IsEmpty()) draining2 = false;
|
||||
if (draining3 && StateMachine.Tank3.IsEmpty()) draining3 = false;
|
||||
}
|
||||
|
||||
/// Close all drain valves
|
||||
if (drainValves.Count > 0)
|
||||
{
|
||||
State.Create("Close all drain valves")
|
||||
.AddOperation(StateMachine.ControlBoard.SetValvesOp(null, drainValves))
|
||||
.EnterState();
|
||||
while (StateMachine.WaitRunDevsRunOps().Contains(Event.ValvesBusy)) { }
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
/// Shut down the state machine
|
||||
///
|
||||
Bridge.OnActivity(this, Strings.Shutting_down_devices); /// Activity message
|
||||
|
||||
State.Create("No operations").EnterState(); /// Stop all operations
|
||||
StateMachine.WaitRunDevsRunOps(true);
|
||||
|
||||
BenchControl.StateMachine.StopDevices(); /// Stop all devices - phase 1
|
||||
Thread.Sleep(100);
|
||||
BenchControl.StateMachine.StopDevices2(); /// Stop all devices - phase 2
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a new empty batch results from the procedure
|
||||
/// </summary>
|
||||
/// <param name="newBatchNr">New batch number</param>
|
||||
/// <param name="procedure">Selected procedure</param>
|
||||
/// <returns>Created BatchResults</returns>
|
||||
Results.BatchResults CreateNewBatchResults(int newBatchNr, Procedure procedure)
|
||||
{
|
||||
///
|
||||
/// Prepare new water meters
|
||||
///
|
||||
foreach (var wm in WaterMeters) wm.ClearData(); /// Clean water meter data
|
||||
|
||||
bool compound = (StateMachine.Procedure.MetersKind == MetersKind.Combined);
|
||||
bool heatMeters = (StateMachine.Procedure.MetersKind == MetersKind.HeatMeter);
|
||||
int waterMetersCount = Math.Min(WaterMeters.Count, heatMeters ? Config.Data.HeatMetersCount : (compound ? Config.Data.CompoundWMsCount : Config.Data.WMsCount));
|
||||
///
|
||||
Results.Entities.WaterMeterData[] waterMeterData = new Results.Entities.WaterMeterData[waterMetersCount];
|
||||
///
|
||||
int[] waterMeterParts = new int[waterMetersCount];
|
||||
for (int wmNr = 0; wmNr < waterMetersCount; wmNr++)
|
||||
{
|
||||
/// WR10 .. WR15 configuration specific code (iPerl head component name)
|
||||
TBF.BenchControl.TestMethods.iPerlCommunication.iPerlHead.IperlHead iHead =
|
||||
TbfComponents.FindComponent(string.Format("iPerl{0}", wmNr + 1)) as TBF.BenchControl.TestMethods.iPerlCommunication.iPerlHead.IperlHead;
|
||||
|
||||
int ix = compound ? (2 * wmNr) : wmNr;
|
||||
if (WaterMeters.Count > ix)
|
||||
{
|
||||
waterMeterParts[wmNr] = Utils.PartNr(wmNr + 1, compound);
|
||||
waterMeterData[wmNr] = new Results.Entities.WaterMeterData()
|
||||
{
|
||||
ProductName = WaterMeters[ix].ProductName,
|
||||
Producer = WaterMeters[ix].Producer,
|
||||
|
||||
L = WaterMeters[ix].L,
|
||||
DN = WaterMeters[ix].DN,
|
||||
Mounting = WaterMeters[ix].Mounting,
|
||||
|
||||
NewQnames = WaterMeters[ix].NewQnames,
|
||||
Q4_Qmax = WaterMeters[ix].Q4_Qmax,
|
||||
Q3_Qn = WaterMeters[ix].Q3_Qn,
|
||||
Q2_Qt = WaterMeters[ix].Q2_Qt,
|
||||
Q1_Qmin = WaterMeters[ix].Q1_Qmin,
|
||||
|
||||
MetrologicalClass = WaterMeters[ix].MetrologicalClass,
|
||||
TemperatureClass = WaterMeters[ix].TemperatureClass,
|
||||
PressureLossClass = WaterMeters[ix].PressureLossClass,
|
||||
MaxAdmissiblePressure = WaterMeters[ix].MaxAdmissiblePressure,
|
||||
FlowProfileSensitivityClass = WaterMeters[ix].FlowProfileSensitivityClass,
|
||||
|
||||
ApprovalInfo = WaterMeters[ix].ApprovalInfo,
|
||||
Certificate = WaterMeters[ix].Certificate,
|
||||
|
||||
PulsesPerLtr = WaterMeters[ix].PulsesPerLtr,
|
||||
Medium = WaterMeters[ix].Medium,
|
||||
Text1 = WaterMeters[ix].Text1,
|
||||
Text2 = WaterMeters[ix].Text2,
|
||||
Text3 = WaterMeters[ix].Text3,
|
||||
Text4 = WaterMeters[ix].Text4,
|
||||
Text5 = WaterMeters[ix].Text5,
|
||||
|
||||
Compound = compound,
|
||||
HeatMeter = heatMeters,
|
||||
#if ORACLE_DB
|
||||
WMTypeId = (iHead != null) ? iHead.WMType_ID : 0,
|
||||
#endif
|
||||
};
|
||||
}
|
||||
|
||||
int auxIx = 2 * wmNr + 1;
|
||||
if (compound && WaterMeters.Count > auxIx)
|
||||
{
|
||||
waterMeterData[wmNr].ProducerAux = WaterMeters[auxIx].Producer;
|
||||
waterMeterData[wmNr].Q3_Qn_Aux = WaterMeters[auxIx].Q3_Qn;
|
||||
waterMeterData[wmNr].MetrologicalClassAux = WaterMeters[auxIx].MetrologicalClass;
|
||||
waterMeterData[wmNr].ApprovalInfoAux = WaterMeters[auxIx].ApprovalInfo;
|
||||
}
|
||||
}
|
||||
|
||||
/// Prepare empty results
|
||||
return Results.BatchResults.NewFromProcedure(newBatchNr,
|
||||
(BenchInfo != null) ? BenchInfo.TestBenchId : 1,
|
||||
(BenchInfo != null) ? BenchInfo.TestBenchName : "testbench",
|
||||
(BenchInfo != null) ? BenchInfo.Address1 : string.Empty,
|
||||
(BenchInfo != null) ? BenchInfo.Address2 : string.Empty,
|
||||
(BenchInfo != null) ? BenchInfo.Address3 : string.Empty,
|
||||
(BenchInfo != null) ? BenchInfo.Address4 : string.Empty,
|
||||
(BenchInfo != null) ? BenchInfo.Address5 : string.Empty,
|
||||
Users.GlobalData.CurrentUser.ToEncodedStr(),
|
||||
Users.GlobalData.CurrentUser.Number,
|
||||
Program.Version,
|
||||
StateMachine.Procedure,
|
||||
waterMeterData,
|
||||
waterMeterParts,
|
||||
Formulas.DensityCorrection(Config.Formulas.RealDensity(),
|
||||
Config.Formulas.AtTemperature()));
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Reload batch results from Results database given the batch number
|
||||
/// </summary>
|
||||
/// <param name="oriBatchNr">Original batch number</param>
|
||||
/// <param name="newBatchNr">New unique batch number</param>
|
||||
/// <param name="procedure">Reloaded procedure</param>
|
||||
/// <returns></returns>
|
||||
void RestoreBatchResults(int oriBatchNr, ref Results.BatchResults batchResults)
|
||||
{
|
||||
Batch oriBatch = Results.DB.LoadBatch(oriBatchNr);
|
||||
|
||||
if (oriBatch == null) return;
|
||||
|
||||
batchResults.Batch.StartTime = oriBatch.StartTime;
|
||||
batchResults.Batch.TestBenchId = (BenchInfo != null) ? BenchInfo.TestBenchId : 1;
|
||||
batchResults.Batch.TestBenchName = (BenchInfo != null) ? BenchInfo.TestBenchName : "testbench";
|
||||
|
||||
foreach (var testRslt in batchResults.Batch.TestRslts)
|
||||
{
|
||||
foreach (var oriTstRslt in oriBatch.TestRslts)
|
||||
{
|
||||
if (testRslt.Name() == oriTstRslt.Name() &&
|
||||
testRslt.Part == oriTstRslt.Part &&
|
||||
testRslt.RepetitionNr == oriTstRslt.RepetitionNr)
|
||||
{
|
||||
testRslt.CopyContentFrom(oriTstRslt);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < batchResults.Batch.WaterMeters.Count; i++)
|
||||
{
|
||||
WaterMeter wm = batchResults.Batch.WaterMeters[i];
|
||||
wm.Disabled = true;
|
||||
foreach (var wm2 in oriBatch.WaterMeters)
|
||||
{
|
||||
if (wm.WMPosition == wm2.WMPosition)
|
||||
{
|
||||
wm.CopyContentFrom(wm2);
|
||||
wm.Disabled = false;
|
||||
#if ORACLE_DB
|
||||
wm.WaterMeterData.WMTypeId = wm2.WaterMeterData.WMTypeId;
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void CollectSimultSteps()
|
||||
{
|
||||
///
|
||||
/// Collect steps (e.g. iPerl communication) to be done simultaneously with purging
|
||||
///
|
||||
simultWithPurgingCount = 0;
|
||||
simultWithPurgingCfg = null;
|
||||
simultWithPurgingTests.Clear();
|
||||
simultWithPurgingParams.Clear();
|
||||
///
|
||||
foreach (var test in StateMachine.Tests)
|
||||
{
|
||||
Generic.IComponent testMethodComp = TbfComponents.FindComponent(test.Method);
|
||||
if (testMethodComp == null) break;
|
||||
|
||||
testMethodComp.Cfg.LoadTestParamsFromDB(test);
|
||||
|
||||
ISimultTestMethod simultTest = testMethodComp as ISimultTestMethod;
|
||||
MetersPath sensPath = StateMachine.GetMetersPath(test);
|
||||
|
||||
if (simultTest == null || !simultTest.SimultWithPrevious || sensPath == null) break;
|
||||
|
||||
if (simultWithPurgingCount == 0)
|
||||
{
|
||||
simultWithPurgingCfg = simultTest.Cfg;
|
||||
}
|
||||
else if (simultTest.Cfg != simultWithPurgingCfg)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
simultWithPurgingTests.Add(test);
|
||||
simultWithPurgingParams.Add(testMethodComp.Cfg.GetRuntimeTestParamsProvider().Clone() as Generic.ITestParams);
|
||||
simultWithPurgingCount++;
|
||||
}
|
||||
|
||||
///
|
||||
/// Collect steps (e.g. iPerl communication) to be done simultaneously with evacuation
|
||||
///
|
||||
simultWithEvacuationCount = 0;
|
||||
simultWithEvacuationCfg = null;
|
||||
simultWithEvacuationTests.Clear();
|
||||
simultWithEvacuationParams.Clear();
|
||||
///
|
||||
for (int i = StateMachine.Tests.Count - 1; i >= simultWithPurgingCount; i--)
|
||||
{
|
||||
var test = StateMachine.Tests[i];
|
||||
|
||||
Generic.IComponent testMethodComp = TbfComponents.FindComponent(test.Method);
|
||||
if (testMethodComp == null) break;
|
||||
|
||||
testMethodComp.Cfg.LoadTestParamsFromDB(test);
|
||||
|
||||
ISimultTestMethod simultTest = testMethodComp as ISimultTestMethod;
|
||||
MetersPath sensPath = StateMachine.GetMetersPath(test);
|
||||
|
||||
if (simultTest == null || !simultTest.SimultWithNext || sensPath == null) break;
|
||||
|
||||
if (simultWithEvacuationCount == 0)
|
||||
{
|
||||
simultWithEvacuationCfg = simultTest.Cfg;
|
||||
}
|
||||
else if (simultTest.Cfg != simultWithEvacuationCfg)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
simultWithEvacuationTests.Insert(0, test);
|
||||
simultWithEvacuationParams.Insert(0, testMethodComp.Cfg.GetRuntimeTestParamsProvider().Clone() as Generic.ITestParams);
|
||||
simultWithEvacuationCount++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Executes steps of a evacuation sequence
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// Event.Done Transition sequence completed OK
|
||||
/// Event.UiCmdStop Transition sequence interrupted by the STOP on-screen button
|
||||
/// Event.Error Error (e.g. RegulValveTimeOut returned by Run() of SetRegulValvePositionOp)
|
||||
/// </returns>
|
||||
Event DoEvacuation(TransitionSequence purgeEnd)
|
||||
{
|
||||
IList<Event> e;
|
||||
|
||||
if (simultWithEvacuationCount > 0)
|
||||
{
|
||||
/// Open iPerlCommunicationForm
|
||||
ProcessData.RegisterReaders = StateMachine.GetMetersPath(simultWithEvacuationTests[0]).RegisterReaders;
|
||||
Program.MainWnd.Invoke(new iPerlCommFormDlgt(OpenIPerlCommForm), new object[] { this, simultWithEvacuationCfg, simultWithEvacuationTests, simultWithEvacuationParams });
|
||||
}
|
||||
|
||||
//--------------------------------------------------------
|
||||
benchFilled = false; /// because evacuation sequence started
|
||||
///
|
||||
switch (Transition(purgeEnd, TransitionContext.PurgeEnd))
|
||||
{
|
||||
case Event.Error:
|
||||
if (simultWithEvacuationCount > 0) CloseIPerlCommForm();
|
||||
return Event.Error;
|
||||
|
||||
case Event.UiCmdStop:
|
||||
if (simultWithEvacuationCount > 0) CloseIPerlCommForm();
|
||||
return Event.UiCmdStop;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (simultWithEvacuationCount > 0)
|
||||
{
|
||||
///
|
||||
/// Wait until iPerl communications are completed
|
||||
///
|
||||
bool completed = !(modelessDlg is GenericDevices.IHasCompleted)
|
||||
|| (modelessDlg as GenericDevices.IHasCompleted).Completed;
|
||||
if (!completed)
|
||||
{
|
||||
State.Create("MainSeq : Wait until the entry form is closed")
|
||||
.AddOperation(checkUiOp)
|
||||
.EnterState();
|
||||
do
|
||||
{
|
||||
e = StateMachine.WaitRunDevsRunOps();
|
||||
if (e.Contains(Event.UiCmdStop))
|
||||
{
|
||||
CloseIPerlCommForm();
|
||||
return Event.UiCmdStop;
|
||||
}
|
||||
|
||||
completed = (modelessDlg as GenericDevices.IHasCompleted).Completed;
|
||||
}
|
||||
while (!completed);
|
||||
}
|
||||
|
||||
modelessDlg = null;
|
||||
}
|
||||
|
||||
Bridge.Bench2UI(ButtonsEtc.ShowBenchEmpty);
|
||||
|
||||
return Event.Done;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
840
TBF/BenchControl/Sequences/MainSeqUtils.cs
Normal file
840
TBF/BenchControl/Sequences/MainSeqUtils.cs
Normal file
@ -0,0 +1,840 @@
|
||||
///
|
||||
/// Copyright (c) 2020 Sensus Slovensko a.s.
|
||||
///
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using Config.Entities;
|
||||
using TBF.BenchControl.GenericDevices;
|
||||
using TBF.BenchControl.Operations;
|
||||
using TBF.Boxes;
|
||||
using TBF.Resources;
|
||||
using TBF.UiBridge;
|
||||
using Results.Entities;
|
||||
|
||||
namespace TBF.BenchControl.Sequences
|
||||
{
|
||||
partial class MainSeq
|
||||
{
|
||||
/// <summary>
|
||||
/// Wrapper
|
||||
/// </summary>
|
||||
IList<string> ServeCalendarEventsInvokeXY(Config.CalendarEvent.AutoAction selectedAction, int maxCount = 1)
|
||||
{
|
||||
return TBF.UI.Calendar.CalendarTabPageCtrl.ServeCalendarEventsInvokeXY(selectedAction, maxCount);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Unconditionally wait for OK button
|
||||
/// </summary>
|
||||
void WaitForOkButton()
|
||||
{
|
||||
State.Create("MainSeq : Press OK to start the system")
|
||||
.AddOperation(new BenchControl.Operations.MessageBoxOp(Strings.Start_the_test_bench, System.Drawing.Color.OliveDrab))
|
||||
.EnterState();
|
||||
|
||||
while (!StateMachine.WaitRunDevsRunOps().Contains(Event.OK)) { }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Unconditionally set valves to default position
|
||||
/// </summary>
|
||||
void SetValvesToDefaultState()
|
||||
{
|
||||
State.Create("MainSeq : Setting valves to default positions")
|
||||
.AddOperation(StateMachine.ControlBoard.SetValvesOp(StateMachine.DefaultValvesOpen, StateMachine.DefaultValvesClose))
|
||||
.EnterState();
|
||||
|
||||
while (StateMachine.WaitRunDevsRunOps().Contains(Event.ValvesBusy)) { }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test communication with all scales that support S/N read operation
|
||||
/// </summary>
|
||||
/// <param name="scaleName">Name of a scale that failed</param>
|
||||
/// <param name="message">Message in case of a failure</param>
|
||||
/// <returns>true = Test passed, all scales communicate OK</returns>
|
||||
bool TestCommunicationWithScales(out string scaleName, out string message)
|
||||
{
|
||||
///
|
||||
/// Read S/N-s from scales (cannot be stopped, but is limitted to Scales count x 3s (=timeout)
|
||||
///
|
||||
IScaleOrTank[] tanks = new IScaleOrTank[] { StateMachine.Tank1, StateMachine.Tank2, StateMachine.Tank3 };
|
||||
|
||||
foreach (var tank in tanks)
|
||||
{
|
||||
if (tank is IScale)
|
||||
{
|
||||
IScale scale = tank as IScale;
|
||||
string sn = string.Empty;
|
||||
IOperation getSNOp = scale.GetSerNumOp(ref sn);
|
||||
|
||||
if (getSNOp != null)
|
||||
{
|
||||
const int nrRetries = 3;
|
||||
|
||||
for (int i = 1; i <= nrRetries; i++)
|
||||
{
|
||||
IList<Event> e;
|
||||
bool error = false;
|
||||
bool timeout = false;
|
||||
|
||||
State.Create(string.Format("MainSeq : Reading S/N of scale {0} trial {1}", scale.Name, i))
|
||||
.AddOperation(getSNOp)
|
||||
.AddOperation(new Operations.TimerOp(2))
|
||||
.EnterState();
|
||||
do
|
||||
{
|
||||
e = StateMachine.WaitRunDevsRunOps();
|
||||
if (e.Contains(Event.Error))
|
||||
{
|
||||
if (i == nrRetries)
|
||||
{
|
||||
///
|
||||
/// All retries completed => the scale failed
|
||||
///
|
||||
scaleName = scale.Name;
|
||||
message = Strings.Scale_communication_error;
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
/// The scale failed => try one more time
|
||||
error = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (e.Contains(Event.Busy) && e.Contains(Event.TimerExpired))
|
||||
{
|
||||
if (i == nrRetries)
|
||||
{
|
||||
///
|
||||
/// All retries completed, the scale failed
|
||||
///
|
||||
scaleName = scale.Name;
|
||||
message = Strings.Scale_communication_timeout;
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
/// The scale failed => try one more time
|
||||
timeout = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
while (e.Contains(Event.Busy));
|
||||
|
||||
if (!error && !timeout)
|
||||
{
|
||||
/// This scale communicates OK, break "for (int i = ... " loop
|
||||
if (!string.IsNullOrEmpty(sn)) log.WarnFormat("Scale {0} : s/n = {1}", scale.Name, sn);
|
||||
break; ///
|
||||
}
|
||||
|
||||
/// Wait one state machine tick (1 second), kreep retrying, stay inside "for (int i = ... " loop
|
||||
State.Create(string.Format("MainSeq : Reading S/N of scale {0}", scale.Name)).EnterState();
|
||||
StateMachine.WaitRunDevsRunOps();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
/// All scales communicate OK, test passed
|
||||
///
|
||||
scaleName = string.Empty;
|
||||
message = string.Empty;
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <returns>true = OK, false = error</returns>
|
||||
bool DrainTanks()
|
||||
{
|
||||
IList<Event> e;
|
||||
|
||||
///
|
||||
/// Enable stop draining buttons
|
||||
///
|
||||
Bridge.Bench2UI(((StateMachine.DrainValve1 != null) ? ButtonsEtc.DrainTankBtn1Hi : 0) |
|
||||
((StateMachine.DrainValve2 != null) ? ButtonsEtc.DrainTankBtn2Hi : 0) |
|
||||
((StateMachine.DrainValve3 != null) ? ButtonsEtc.DrainTankBtn3Hi : 0));
|
||||
|
||||
///
|
||||
/// Determine lists of drain valves and drain times (max. of all tank drain times)
|
||||
///
|
||||
IList<IValve> fullDrainValves = new List<IValve>();
|
||||
IList<IValve> secondHalfDrainValves = new List<IValve>();
|
||||
IList<IValve> allDrainValves = new List<IValve>();
|
||||
int totalDrainTime = 0;
|
||||
int maxDrainTimeFor2VlvTanks = 0;
|
||||
bool areTwoDrainPhases = false;
|
||||
foreach (IScaleOrTank tank in new IScaleOrTank[] { StateMachine.Tank1, StateMachine.Tank2, StateMachine.Tank3 })
|
||||
{
|
||||
if (tank != null && tank.DrainValve != null)
|
||||
{
|
||||
if (tank.EmptyTimeSec > totalDrainTime) totalDrainTime = tank.EmptyTimeSec;
|
||||
if (tank.DrainValve2 != null)
|
||||
{
|
||||
areTwoDrainPhases = true;
|
||||
if (tank.EmptyTimeSec > maxDrainTimeFor2VlvTanks) maxDrainTimeFor2VlvTanks = tank.EmptyTimeSec;
|
||||
|
||||
if (!secondHalfDrainValves.Contains(tank.DrainValve)) secondHalfDrainValves.Add(tank.DrainValve);
|
||||
if (!fullDrainValves.Contains(tank.DrainValve2)) fullDrainValves.Add(tank.DrainValve2);
|
||||
if (!allDrainValves.Contains(tank.DrainValve)) allDrainValves.Add(tank.DrainValve);
|
||||
if (!allDrainValves.Contains(tank.DrainValve2)) allDrainValves.Add(tank.DrainValve2);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!fullDrainValves.Contains(tank.DrainValve)) fullDrainValves.Add(tank.DrainValve);
|
||||
if (!allDrainValves.Contains(tank.DrainValve)) allDrainValves.Add(tank.DrainValve);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
/// Drain the tanks, two phases if necessary
|
||||
///
|
||||
if (totalDrainTime > 0)
|
||||
{
|
||||
IntBox timerTime = new IntBox(); /// Contains remaining time in each phase
|
||||
int firstPhaseTime = maxDrainTimeFor2VlvTanks / 2;
|
||||
|
||||
State.Create(areTwoDrainPhases ? "MainSeq : Drain tanks - phase 1" : "MainSeq : Drain tanks")
|
||||
.AddOperation(checkUiOp)
|
||||
.AddOperation(new TimerOp(areTwoDrainPhases ? firstPhaseTime : totalDrainTime, timerTime))
|
||||
.AddOperation(StateMachine.ControlBoard.SetValvesOp(fullDrainValves, null))
|
||||
.EnterState();
|
||||
do
|
||||
{
|
||||
int remTime = areTwoDrainPhases ? (timerTime.Val + totalDrainTime - firstPhaseTime) : timerTime.Val;
|
||||
Bridge.OnActivity(this, string.Format("{0} ... {1} {2} {3} {4}", Strings.Emptying_tank, remTime / 60, "min", remTime % 60, Strings.sec));
|
||||
|
||||
e = StateMachine.WaitRunDevsRunOps();
|
||||
if (e.Contains(Event.Error)) return false;
|
||||
bool stopDrainingCmd = e.Contains(Event.UiCmdStopDrainingTank1) || e.Contains(Event.UiCmdStopDrainingTank2) || e.Contains(Event.UiCmdStopDrainingTank3);
|
||||
if (stopDrainingCmd && !e.Contains(Event.ValvesBusy) && !e.Contains(Event.CameraBusy)) break;
|
||||
}
|
||||
while (e.Contains(Event.TimerBusy) || e.Contains(Event.CameraBusy) || e.Contains(Event.ValvesBusy));
|
||||
|
||||
if (areTwoDrainPhases)
|
||||
{
|
||||
State.Create("MainSeq : Drain tanks - phase 2")
|
||||
.AddOperation(checkUiOp)
|
||||
.AddOperation(new TimerOp(totalDrainTime - firstPhaseTime, timerTime))
|
||||
.AddOperation(StateMachine.ControlBoard.SetValvesOp(secondHalfDrainValves, null))
|
||||
.EnterState();
|
||||
do
|
||||
{
|
||||
int remTime = timerTime.Val;
|
||||
Bridge.OnActivity(this, string.Format("{0} ... {1} {2} {3} {4}", Strings.Emptying_tank, remTime / 60, "min", remTime % 60, Strings.sec));
|
||||
|
||||
e = StateMachine.WaitRunDevsRunOps();
|
||||
if (e.Contains(Event.Error)) return false;
|
||||
bool stopDrainingCmd = e.Contains(Event.UiCmdStopDrainingTank1) || e.Contains(Event.UiCmdStopDrainingTank2) || e.Contains(Event.UiCmdStopDrainingTank3);
|
||||
if (stopDrainingCmd && !e.Contains(Event.ValvesBusy) && !e.Contains(Event.CameraBusy)) break;
|
||||
}
|
||||
while (e.Contains(Event.TimerBusy) || e.Contains(Event.CameraBusy) || e.Contains(Event.ValvesBusy));
|
||||
}
|
||||
|
||||
Bridge.OnActivity(this, Strings.Emptying_tank);
|
||||
|
||||
State stopDraining = State.Create("MainSeq : Stop draining water tanks")
|
||||
.AddOperation(checkUiOp)
|
||||
.AddOperation(StateMachine.ControlBoard.SetValvesOp(null, allDrainValves))
|
||||
.EnterState();
|
||||
do
|
||||
{
|
||||
e = StateMachine.WaitRunDevsRunOps();
|
||||
if (e.Contains(Event.Error)) return false;
|
||||
}
|
||||
while (e.Contains(Event.ValvesBusy));
|
||||
}
|
||||
|
||||
return true; /// OK
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This function is called after a procedure was selected and all components procedure parameters of components were loaded
|
||||
/// </summary>
|
||||
void ClearSessionData()
|
||||
{
|
||||
///
|
||||
/// Clear iperlhead data (including PCB Number, avoid double use)
|
||||
///
|
||||
foreach (var cmpnt in StateMachine.Components)
|
||||
{
|
||||
if (cmpnt is TestMethods.iPerlCommunication.iPerlHead.IperlHead)
|
||||
{
|
||||
(cmpnt as TestMethods.iPerlCommunication.iPerlHead.IperlHead).ClearData();
|
||||
}
|
||||
}
|
||||
|
||||
IsQ2PreCorrectionCalculated = false;
|
||||
CalculatedQ2PreCorrectionLR = 0;
|
||||
CalculatedQ2PreCorrectionRL = 0;
|
||||
RawTestInfos = null;
|
||||
CompleteTestInfos = null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Idle loop to make a procedure or test selection.
|
||||
/// Handles tank emptying, camera test.
|
||||
/// </summary>
|
||||
/// <param name="context">Context where MakeSelection() is called</param>
|
||||
/// <returns>
|
||||
/// Selection.PurgeBegin, PurgeEnd, Break, Cycle, Test, Q1, Q2, Q3 or SaveResults
|
||||
/// </returns>
|
||||
Selection MakeSelection(MKSelContext context)
|
||||
{
|
||||
log.WarnFormat("MakeSelection({0})", context);
|
||||
|
||||
bool restoreIntrptdSessionEnabled = (context == MKSelContext.ProcedureNotSelected) && File.Exists(ProcessData.PDataFileName);
|
||||
|
||||
/// Tank emptying valves states
|
||||
bool draining1 = false;
|
||||
bool draining2 = false;
|
||||
bool draining3 = false;
|
||||
|
||||
/// Measured masses to control emptying
|
||||
DoubleBox mass1 = new DoubleBox();
|
||||
DoubleBox mass2 = new DoubleBox();
|
||||
DoubleBox mass3 = new DoubleBox();
|
||||
|
||||
IList<Event> e;
|
||||
|
||||
while (true)
|
||||
{
|
||||
bool draining = draining1 || draining2 || draining3;
|
||||
|
||||
///
|
||||
/// Activity message
|
||||
///
|
||||
Bridge.OnActivity(this, draining ? Strings.Emptying_tank
|
||||
: ((context == MKSelContext.ProcedureNotSelected) ? Strings.Please_select_a_procedure
|
||||
: Strings.Please_select_a_cycle_a_test_or_empty));
|
||||
|
||||
bool saveResultsActive = (context == MKSelContext.InsideProcedure)
|
||||
&& (StateMachine.Procedure != null)
|
||||
&& (!StateMachine.Procedure.MustBeComplete || BatchRslts.AllTestsDone());
|
||||
|
||||
/// Enable appropriate UI controls and buttons
|
||||
Bridge.Bench2UI(((context == MKSelContext.ProcedureNotSelected) ? ButtonsEtc.ProcedureCmbBoxEn : 0) |
|
||||
ButtonsEtc.TestCmbBoxEn |
|
||||
((context == MKSelContext.InsideProcedure) ? ButtonsEtc.Break : 0) |
|
||||
(restoreIntrptdSessionEnabled ? ButtonsEtc.RestoreSession : 0) |
|
||||
(saveResultsActive ? ButtonsEtc.AcceptResultsBtnEn : 0) |
|
||||
(draining ? 0 : ButtonsEtc.StartCycleBtnEn) |
|
||||
(draining ? 0 : ButtonsEtc.StartTestBtnsEn) |
|
||||
(draining ? 0 : ButtonsEtc.PurgeBeginBtnEn) |
|
||||
(draining ? 0 : ((context == MKSelContext.InsideProcedure) ? ButtonsEtc.PurgeEndBtnEn : 0)) |
|
||||
((StateMachine.DrainValve1 == null) ? 0 : (draining1 ? ButtonsEtc.DrainTankBtn1Hi : ButtonsEtc.DrainTankBtn1En)) |
|
||||
((StateMachine.DrainValve2 == null) ? 0 : (draining2 ? ButtonsEtc.DrainTankBtn2Hi : ButtonsEtc.DrainTankBtn2En)) |
|
||||
((StateMachine.DrainValve3 == null) ? 0 : (draining3 ? ButtonsEtc.DrainTankBtn3Hi : ButtonsEtc.DrainTankBtn3En)));
|
||||
|
||||
|
||||
State.Create("MainSeq : Select an activity")
|
||||
.AddOperation(checkUiOp)
|
||||
.AddOperation(StateMachine.BenchWaitingOp)
|
||||
.AddOperation((StateMachine.Tank1 is IScale) ? (StateMachine.Tank1 as IScale).ReadMassOp(ref mass1) : null)
|
||||
.AddOperation((StateMachine.Tank2 is IScale) ? (StateMachine.Tank2 as IScale).ReadMassOp(ref mass2) : null)
|
||||
.AddOperation((StateMachine.Tank3 is IScale) ? (StateMachine.Tank3 as IScale).ReadMassOp(ref mass3) : null)
|
||||
.EnterState();
|
||||
do
|
||||
{
|
||||
e = StateMachine.WaitRunDevsRunOps();
|
||||
|
||||
/// Handled inside MakeSelection() inside the selection loop
|
||||
if (e.Contains(Event.Error)) break;
|
||||
if (!draining1 && e.Contains(Event.UiCmdDrainTank1)) break;
|
||||
if (!draining2 && e.Contains(Event.UiCmdDrainTank2)) break;
|
||||
if (!draining3 && e.Contains(Event.UiCmdDrainTank3)) break;
|
||||
if (draining1 && e.Contains(Event.UiCmdStopDrainingTank1)) break;
|
||||
if (draining2 && e.Contains(Event.UiCmdStopDrainingTank2)) break;
|
||||
if (draining3 && e.Contains(Event.UiCmdStopDrainingTank3)) break;
|
||||
if (draining1 && StateMachine.Tank1.IsEmpty()) break;
|
||||
if (draining2 && StateMachine.Tank2.IsEmpty()) break;
|
||||
if (draining3 && StateMachine.Tank3.IsEmpty()) break;
|
||||
|
||||
/// Quit the selection loop and leave MakeSelection()
|
||||
if (e.Contains(Event.UiCmdShutdown)) return Selection.Shutdown;
|
||||
if (context == MKSelContext.InsideProcedure
|
||||
&& e.Contains(Event.UiCmdBreak)) return Selection.Break;
|
||||
if (e.Contains(Event.UiCmdPurgeBegin)) return Selection.PurgeBegin;
|
||||
if (e.Contains(Event.UiCmdPurgeEnd)) return Selection.PurgeEnd;
|
||||
if (e.Contains(Event.UiCmdStartCycle)) return Selection.Cycle;
|
||||
if (e.Contains(Event.UiCmdStartTest)) return Selection.Test;
|
||||
if (e.Contains(Event.UiCmdStartQ1)) return Selection.Q1;
|
||||
if (e.Contains(Event.UiCmdStartQ2)) return Selection.Q2;
|
||||
if (e.Contains(Event.UiCmdStartQ3)) return Selection.Q3;
|
||||
if (e.Contains(Event.UiCmdAcceptResults)) return Selection.SaveResults;
|
||||
if (e.Contains(Event.UiCmdReloadBatch)) return Selection.RestoreBatch;
|
||||
if (e.Contains(Event.UiCmdReloadAndFixBatch)) return Selection.RestoreAndFixBatch;
|
||||
if (restoreIntrptdSessionEnabled
|
||||
&& e.Contains(Event.UiCmdRestoreSession)) return Selection.RestoreInterruptedSession;
|
||||
}
|
||||
while (true);
|
||||
|
||||
|
||||
if (e.Contains(Event.Error))
|
||||
{
|
||||
///------------------------------------
|
||||
Bridge.OnActivity(this, Strings.Error);
|
||||
///------------------------------------
|
||||
State.Create("MainSeq : ERROR state")
|
||||
.AddOperation(checkUiOp)
|
||||
.AddOperation(StateMachine.BenchErrorOp)
|
||||
.EnterState();
|
||||
do
|
||||
{
|
||||
e = StateMachine.WaitRunDevsRunOps();
|
||||
}
|
||||
while (!e.Contains(Event.UiCmdShutdown));
|
||||
|
||||
return Selection.Shutdown;
|
||||
}
|
||||
else
|
||||
{
|
||||
string stateText = "MainSeq : ";
|
||||
IList<IValve> openValves = new List<IValve>();
|
||||
IList<IValve> closeValves = new List<IValve>();
|
||||
|
||||
if (draining1 && (StateMachine.Tank1.IsEmpty() || e.Contains(Event.UiCmdStopDrainingTank1)))
|
||||
{
|
||||
draining1 = false;
|
||||
closeValves.Add(StateMachine.DrainValve1);
|
||||
stateText = stateText + "close tank 1, ";
|
||||
}
|
||||
else if (draining2 && (StateMachine.Tank2.IsEmpty() || e.Contains(Event.UiCmdStopDrainingTank2)))
|
||||
{
|
||||
draining2 = false;
|
||||
closeValves.Add(StateMachine.DrainValve2);
|
||||
stateText = stateText + "close tank 2, ";
|
||||
}
|
||||
else if (draining3 && (StateMachine.Tank3.IsEmpty() || e.Contains(Event.UiCmdStopDrainingTank3)))
|
||||
{
|
||||
draining3 = false;
|
||||
closeValves.Add(StateMachine.DrainValve3);
|
||||
stateText = stateText + "close tank 3, ";
|
||||
}
|
||||
else if (!draining1 && e.Contains(Event.UiCmdDrainTank1))
|
||||
{
|
||||
draining1 = true;
|
||||
openValves.Add(StateMachine.DrainValve1);
|
||||
stateText = stateText + "open tank 1, ";
|
||||
}
|
||||
else if (!draining2 && e.Contains(Event.UiCmdDrainTank2))
|
||||
{
|
||||
draining2 = true;
|
||||
openValves.Add(StateMachine.DrainValve2);
|
||||
stateText = stateText + "open tank 2, ";
|
||||
}
|
||||
else if (!draining3 && e.Contains(Event.UiCmdDrainTank3))
|
||||
{
|
||||
draining3 = true;
|
||||
openValves.Add(StateMachine.DrainValve3);
|
||||
stateText = stateText + "open tank 3, ";
|
||||
}
|
||||
|
||||
draining = draining1 || draining2 || draining3;
|
||||
if (draining) Bridge.OnActivity(this, Strings.Emptying_tank);
|
||||
|
||||
Bridge.Bench2UI(((context == MKSelContext.ProcedureNotSelected) ? ButtonsEtc.ProcedureCmbBoxEn : 0) |
|
||||
((StateMachine.DrainValve1 == null) ? 0 : (draining1 ? ButtonsEtc.DrainTankBtn1Hi : ButtonsEtc.DrainTankBtn1En)) |
|
||||
((StateMachine.DrainValve2 == null) ? 0 : (draining2 ? ButtonsEtc.DrainTankBtn2Hi : ButtonsEtc.DrainTankBtn2En)) |
|
||||
((StateMachine.DrainValve3 == null) ? 0 : (draining3 ? ButtonsEtc.DrainTankBtn3Hi : ButtonsEtc.DrainTankBtn3En)));
|
||||
|
||||
State.Create(stateText)
|
||||
.AddOperation(StateMachine.ControlBoard.SetValvesOp(openValves, closeValves))
|
||||
.EnterState();
|
||||
do
|
||||
{
|
||||
e = StateMachine.WaitRunDevsRunOps();
|
||||
}
|
||||
while (e.Contains(Event.ValvesBusy));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Shutdown(bool skipTankDraining = false)
|
||||
{
|
||||
log.WarnFormat(string.Format("Shutdown(skipTankDraining={0})", skipTankDraining));
|
||||
|
||||
StateMachine.MachineState = MachineState.ShuttingDown; /// TBF shut down cannot be aborted from now on
|
||||
Bridge.Bench2UI(0); /// All buttons off
|
||||
|
||||
if (!skipTankDraining)
|
||||
{
|
||||
/// Drain time
|
||||
int maxDrainTime = 0;
|
||||
if ((StateMachine.Tank1 != null) && (StateMachine.Tank1.EmptyTimeSec > maxDrainTime)) maxDrainTime = StateMachine.Tank1.EmptyTimeSec;
|
||||
if ((StateMachine.Tank2 != null) && (StateMachine.Tank2.EmptyTimeSec > maxDrainTime)) maxDrainTime = StateMachine.Tank2.EmptyTimeSec;
|
||||
if ((StateMachine.Tank3 != null) && (StateMachine.Tank3.EmptyTimeSec > maxDrainTime)) maxDrainTime = StateMachine.Tank3.EmptyTimeSec;
|
||||
|
||||
/// Drain valves
|
||||
IList<IValve> drainValves = new List<IValve>();
|
||||
if (StateMachine.DrainValve1 != null) drainValves.Add(StateMachine.DrainValve1);
|
||||
if (StateMachine.DrainValve2 != null) drainValves.Add(StateMachine.DrainValve2);
|
||||
if (StateMachine.DrainValve3 != null) drainValves.Add(StateMachine.DrainValve3);
|
||||
|
||||
/// Open all drain valves
|
||||
if (drainValves.Count > 0)
|
||||
{
|
||||
Bridge.OnActivity(this, Strings.Emptying_tank); /// Activity message
|
||||
|
||||
State.Create("Open all drain valves")
|
||||
.AddOperation(StateMachine.ControlBoard.SetValvesOp(drainValves, null))
|
||||
.EnterState();
|
||||
while (StateMachine.WaitRunDevsRunOps().Contains(Event.ValvesBusy)) { }
|
||||
}
|
||||
|
||||
/// Tank emptying valves states
|
||||
bool draining1 = (StateMachine.DrainValve1 != null);
|
||||
bool draining2 = (StateMachine.DrainValve2 != null);
|
||||
bool draining3 = (StateMachine.DrainValve3 != null);
|
||||
|
||||
int drainingStartTime = StateMachine.Time;
|
||||
|
||||
/// Quit the following loop when time expires or all tanks are empty
|
||||
while ((StateMachine.Time < drainingStartTime + maxDrainTime) && (draining1 || draining2 || draining3))
|
||||
{
|
||||
int remTime = drainingStartTime + maxDrainTime - StateMachine.Time;
|
||||
Bridge.OnActivity(this, string.Format("{0} ... {1} {2} {3} {4}", Strings.Emptying_tank, remTime / 60, "min", remTime % 60, Strings.sec));
|
||||
|
||||
DoubleBox mass1 = new DoubleBox();
|
||||
DoubleBox mass2 = new DoubleBox();
|
||||
DoubleBox mass3 = new DoubleBox();
|
||||
///
|
||||
State.Create("MainSeq : Reading mass")
|
||||
.AddOperation(checkUiOp)
|
||||
.AddOperation((StateMachine.Tank1 is IScale) ? (StateMachine.Tank1 as IScale).ReadMassOp(ref mass1) : null)
|
||||
.AddOperation((StateMachine.Tank2 is IScale) ? (StateMachine.Tank2 as IScale).ReadMassOp(ref mass2) : null)
|
||||
.AddOperation((StateMachine.Tank3 is IScale) ? (StateMachine.Tank3 as IScale).ReadMassOp(ref mass3) : null)
|
||||
.EnterState();
|
||||
while (StateMachine.WaitRunDevsRunOps().Contains(Event.Busy)) { }
|
||||
|
||||
if (draining1 && StateMachine.Tank1.IsEmpty()) draining1 = false;
|
||||
if (draining2 && StateMachine.Tank2.IsEmpty()) draining2 = false;
|
||||
if (draining3 && StateMachine.Tank3.IsEmpty()) draining3 = false;
|
||||
}
|
||||
|
||||
/// Close all drain valves
|
||||
if (drainValves.Count > 0)
|
||||
{
|
||||
State.Create("Close all drain valves")
|
||||
.AddOperation(StateMachine.ControlBoard.SetValvesOp(null, drainValves))
|
||||
.EnterState();
|
||||
while (StateMachine.WaitRunDevsRunOps().Contains(Event.ValvesBusy)) { }
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
/// Shut down the state machine
|
||||
///
|
||||
Bridge.OnActivity(this, Strings.Shutting_down_devices); /// Activity message
|
||||
|
||||
State.Create("No operations").EnterState(); /// Stop all operations
|
||||
StateMachine.WaitRunDevsRunOps(true);
|
||||
|
||||
BenchControl.StateMachine.StopDevices(); /// Stop all devices - phase 1
|
||||
Thread.Sleep(100);
|
||||
BenchControl.StateMachine.StopDevices2(); /// Stop all devices - phase 2
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a new empty batch results from the procedure
|
||||
/// </summary>
|
||||
/// <param name="newBatchNr">New batch number</param>
|
||||
/// <param name="procedure">Selected procedure</param>
|
||||
/// <returns>Created BatchResults</returns>
|
||||
Results.BatchResults CreateNewBatchResults(int newBatchNr, Procedure procedure)
|
||||
{
|
||||
///
|
||||
/// Prepare new water meters
|
||||
///
|
||||
foreach (var wm in WaterMeters) wm.ClearData(); /// Clean water meter data
|
||||
|
||||
bool compound = (StateMachine.Procedure.MetersKind == MetersKind.Combined);
|
||||
bool heatMeters = (StateMachine.Procedure.MetersKind == MetersKind.HeatMeter);
|
||||
int waterMetersCount = Math.Min(WaterMeters.Count, heatMeters ? Config.Data.HeatMetersCount : (compound ? Config.Data.CompoundWMsCount : Config.Data.WMsCount));
|
||||
///
|
||||
Results.Entities.WaterMeterData[] waterMeterData = new Results.Entities.WaterMeterData[waterMetersCount];
|
||||
///
|
||||
int[] waterMeterParts = new int[waterMetersCount];
|
||||
for (int wmNr = 0; wmNr < waterMetersCount; wmNr++)
|
||||
{
|
||||
/// WR10 .. WR15 configuration specific code (iPerl head component name)
|
||||
TBF.BenchControl.TestMethods.iPerlCommunication.iPerlHead.IperlHead iHead =
|
||||
TbfComponents.FindComponent(string.Format("iPerl{0}", wmNr + 1)) as TBF.BenchControl.TestMethods.iPerlCommunication.iPerlHead.IperlHead;
|
||||
|
||||
int ix = compound ? (2 * wmNr) : wmNr;
|
||||
if (WaterMeters.Count > ix)
|
||||
{
|
||||
waterMeterParts[wmNr] = Utils.PartNr(wmNr + 1, compound);
|
||||
waterMeterData[wmNr] = new Results.Entities.WaterMeterData()
|
||||
{
|
||||
ProductName = WaterMeters[ix].ProductName,
|
||||
Producer = WaterMeters[ix].Producer,
|
||||
|
||||
L = WaterMeters[ix].L,
|
||||
DN = WaterMeters[ix].DN,
|
||||
Mounting = WaterMeters[ix].Mounting,
|
||||
|
||||
NewQnames = WaterMeters[ix].NewQnames,
|
||||
Q4_Qmax = WaterMeters[ix].Q4_Qmax,
|
||||
Q3_Qn = WaterMeters[ix].Q3_Qn,
|
||||
Q2_Qt = WaterMeters[ix].Q2_Qt,
|
||||
Q1_Qmin = WaterMeters[ix].Q1_Qmin,
|
||||
|
||||
MetrologicalClass = WaterMeters[ix].MetrologicalClass,
|
||||
TemperatureClass = WaterMeters[ix].TemperatureClass,
|
||||
PressureLossClass = WaterMeters[ix].PressureLossClass,
|
||||
MaxAdmissiblePressure = WaterMeters[ix].MaxAdmissiblePressure,
|
||||
FlowProfileSensitivityClass = WaterMeters[ix].FlowProfileSensitivityClass,
|
||||
|
||||
ApprovalInfo = WaterMeters[ix].ApprovalInfo,
|
||||
Certificate = WaterMeters[ix].Certificate,
|
||||
|
||||
PulsesPerLtr = WaterMeters[ix].PulsesPerLtr,
|
||||
Medium = WaterMeters[ix].Medium,
|
||||
Text1 = WaterMeters[ix].Text1,
|
||||
Text2 = WaterMeters[ix].Text2,
|
||||
Text3 = WaterMeters[ix].Text3,
|
||||
Text4 = WaterMeters[ix].Text4,
|
||||
Text5 = WaterMeters[ix].Text5,
|
||||
|
||||
Compound = compound,
|
||||
HeatMeter = heatMeters,
|
||||
#if ORACLE_DB
|
||||
WMTypeId = (iHead != null) ? iHead.WMType_ID : 0,
|
||||
#endif
|
||||
};
|
||||
}
|
||||
|
||||
int auxIx = 2 * wmNr + 1;
|
||||
if (compound && WaterMeters.Count > auxIx)
|
||||
{
|
||||
waterMeterData[wmNr].ProducerAux = WaterMeters[auxIx].Producer;
|
||||
waterMeterData[wmNr].Q3_Qn_Aux = WaterMeters[auxIx].Q3_Qn;
|
||||
waterMeterData[wmNr].MetrologicalClassAux = WaterMeters[auxIx].MetrologicalClass;
|
||||
waterMeterData[wmNr].ApprovalInfoAux = WaterMeters[auxIx].ApprovalInfo;
|
||||
}
|
||||
}
|
||||
|
||||
/// Prepare empty results
|
||||
return Results.BatchResults.NewFromProcedure(newBatchNr,
|
||||
(BenchInfo != null) ? BenchInfo.TestBenchId : 1,
|
||||
(BenchInfo != null) ? BenchInfo.TestBenchName : "testbench",
|
||||
(BenchInfo != null) ? BenchInfo.Address1 : string.Empty,
|
||||
(BenchInfo != null) ? BenchInfo.Address2 : string.Empty,
|
||||
(BenchInfo != null) ? BenchInfo.Address3 : string.Empty,
|
||||
(BenchInfo != null) ? BenchInfo.Address4 : string.Empty,
|
||||
(BenchInfo != null) ? BenchInfo.Address5 : string.Empty,
|
||||
Users.GlobalData.CurrentUser.ToEncodedStr(),
|
||||
Users.GlobalData.CurrentUser.Number,
|
||||
Program.Version,
|
||||
StateMachine.Procedure,
|
||||
waterMeterData,
|
||||
waterMeterParts,
|
||||
Config.Formulas.DensityCorrection(Config.Formulas.RealDensity(),
|
||||
Config.Formulas.AtTemperature()));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reload batch results from Results database given the batch number
|
||||
/// </summary>
|
||||
/// <param name="oriBatchNr">Original batch number</param>
|
||||
/// <param name="newBatchNr">New unique batch number</param>
|
||||
/// <param name="procedure">Reloaded procedure</param>
|
||||
/// <returns></returns>
|
||||
void RestoreBatchResults(int oriBatchNr, ref Results.BatchResults batchResults)
|
||||
{
|
||||
Batch oriBatch = Results.DB.LoadBatch(oriBatchNr);
|
||||
|
||||
if (oriBatch == null) return;
|
||||
|
||||
batchResults.Batch.StartTime = oriBatch.StartTime;
|
||||
batchResults.Batch.TestBenchId = (BenchInfo != null) ? BenchInfo.TestBenchId : 1;
|
||||
batchResults.Batch.TestBenchName = (BenchInfo != null) ? BenchInfo.TestBenchName : "testbench";
|
||||
|
||||
foreach (var testRslt in batchResults.Batch.TestRslts)
|
||||
{
|
||||
foreach (var oriTstRslt in oriBatch.TestRslts)
|
||||
{
|
||||
if (testRslt.Name() == oriTstRslt.Name() &&
|
||||
testRslt.Part == oriTstRslt.Part &&
|
||||
testRslt.RepetitionNr == oriTstRslt.RepetitionNr)
|
||||
{
|
||||
testRslt.CopyContentFrom(oriTstRslt);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < batchResults.Batch.WaterMeters.Count; i++)
|
||||
{
|
||||
WaterMeter wm = batchResults.Batch.WaterMeters[i];
|
||||
wm.Disabled = true;
|
||||
foreach (var wm2 in oriBatch.WaterMeters)
|
||||
{
|
||||
if (wm.WMPosition == wm2.WMPosition)
|
||||
{
|
||||
wm.CopyContentFrom(wm2);
|
||||
wm.Disabled = false;
|
||||
#if ORACLE_DB
|
||||
wm.WaterMeterData.WMTypeId = wm2.WaterMeterData.WMTypeId;
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CollectSimultSteps()
|
||||
{
|
||||
///
|
||||
/// Collect steps (e.g. iPerl communication) to be done simultaneously with purging
|
||||
///
|
||||
simultWithPurgingCount = 0;
|
||||
simultWithPurgingCfg = null;
|
||||
simultWithPurgingTests.Clear();
|
||||
simultWithPurgingParams.Clear();
|
||||
///
|
||||
foreach (var test in StateMachine.Tests)
|
||||
{
|
||||
Generic.IComponent testMethodComp = TbfComponents.FindComponent(test.Method);
|
||||
if (testMethodComp == null) break;
|
||||
|
||||
testMethodComp.Cfg.LoadTestParamsFromDB(test);
|
||||
|
||||
ISimultTestMethod simultTest = testMethodComp as ISimultTestMethod;
|
||||
MetersPath sensPath = StateMachine.GetMetersPath(test);
|
||||
|
||||
if (simultTest == null || !simultTest.SimultWithPrevious || sensPath == null) break;
|
||||
|
||||
if (simultWithPurgingCount == 0)
|
||||
{
|
||||
simultWithPurgingCfg = simultTest.Cfg;
|
||||
}
|
||||
else if (simultTest.Cfg != simultWithPurgingCfg)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
simultWithPurgingTests.Add(test);
|
||||
simultWithPurgingParams.Add(testMethodComp.Cfg.GetRuntimeTestParamsProvider().Clone() as Generic.ITestParams);
|
||||
simultWithPurgingCount++;
|
||||
}
|
||||
|
||||
///
|
||||
/// Collect steps (e.g. iPerl communication) to be done simultaneously with evacuation
|
||||
///
|
||||
simultWithEvacuationCount = 0;
|
||||
simultWithEvacuationCfg = null;
|
||||
simultWithEvacuationTests.Clear();
|
||||
simultWithEvacuationParams.Clear();
|
||||
///
|
||||
for (int i = StateMachine.Tests.Count - 1; i >= simultWithPurgingCount; i--)
|
||||
{
|
||||
var test = StateMachine.Tests[i];
|
||||
|
||||
Generic.IComponent testMethodComp = TbfComponents.FindComponent(test.Method);
|
||||
if (testMethodComp == null) break;
|
||||
|
||||
testMethodComp.Cfg.LoadTestParamsFromDB(test);
|
||||
|
||||
ISimultTestMethod simultTest = testMethodComp as ISimultTestMethod;
|
||||
MetersPath sensPath = StateMachine.GetMetersPath(test);
|
||||
|
||||
if (simultTest == null || !simultTest.SimultWithNext || sensPath == null) break;
|
||||
|
||||
if (simultWithEvacuationCount == 0)
|
||||
{
|
||||
simultWithEvacuationCfg = simultTest.Cfg;
|
||||
}
|
||||
else if (simultTest.Cfg != simultWithEvacuationCfg)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
simultWithEvacuationTests.Insert(0, test);
|
||||
simultWithEvacuationParams.Insert(0, testMethodComp.Cfg.GetRuntimeTestParamsProvider().Clone() as Generic.ITestParams);
|
||||
simultWithEvacuationCount++;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Executes steps of a evacuation sequence
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// Event.Done Transition sequence completed OK
|
||||
/// Event.UiCmdStop Transition sequence interrupted by the STOP on-screen button
|
||||
/// Event.Error Error (e.g. RegulValveTimeOut returned by Run() of SetRegulValvePositionOp)
|
||||
/// </returns>
|
||||
Event DoEvacuation(TransitionSequence purgeEnd)
|
||||
{
|
||||
IList<Event> e;
|
||||
|
||||
if (simultWithEvacuationCount > 0)
|
||||
{
|
||||
/// Open iPerlCommunicationForm
|
||||
ProcessData.RegisterReaders = StateMachine.GetMetersPath(simultWithEvacuationTests[0]).RegisterReaders;
|
||||
Program.MainWnd.Invoke(new iPerlCommFormDlgt(OpenIPerlCommForm), new object[] { this, simultWithEvacuationCfg, simultWithEvacuationTests, simultWithEvacuationParams });
|
||||
}
|
||||
|
||||
//--------------------------------------------------------
|
||||
benchFilled = false; /// because evacuation sequence started
|
||||
///
|
||||
switch (Transition(purgeEnd, TransitionContext.PurgeEnd))
|
||||
{
|
||||
case Event.Error:
|
||||
if (simultWithEvacuationCount > 0) CloseIPerlCommForm();
|
||||
return Event.Error;
|
||||
|
||||
case Event.UiCmdStop:
|
||||
if (simultWithEvacuationCount > 0) CloseIPerlCommForm();
|
||||
return Event.UiCmdStop;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (simultWithEvacuationCount > 0)
|
||||
{
|
||||
///
|
||||
/// Wait until iPerl communications are completed
|
||||
///
|
||||
bool completed = !(modelessDlg is GenericDevices.IHasCompleted)
|
||||
|| (modelessDlg as GenericDevices.IHasCompleted).Completed;
|
||||
if (!completed)
|
||||
{
|
||||
State.Create("MainSeq : Wait until the entry form is closed")
|
||||
.AddOperation(checkUiOp)
|
||||
.EnterState();
|
||||
do
|
||||
{
|
||||
e = StateMachine.WaitRunDevsRunOps();
|
||||
if (e.Contains(Event.UiCmdStop))
|
||||
{
|
||||
CloseIPerlCommForm();
|
||||
return Event.UiCmdStop;
|
||||
}
|
||||
|
||||
completed = (modelessDlg as GenericDevices.IHasCompleted).Completed;
|
||||
}
|
||||
while (!completed);
|
||||
}
|
||||
|
||||
modelessDlg = null;
|
||||
}
|
||||
|
||||
Bridge.Bench2UI(ButtonsEtc.ShowBenchEmpty);
|
||||
|
||||
return Event.Done;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -548,7 +548,7 @@ namespace TBF.BenchControl
|
||||
/// Loads selected procedure from the DB.
|
||||
/// Updates StateMachine.Procedure and StateMachine.Tests
|
||||
/// </summary>
|
||||
public static bool LoadProcedure(ISession session, string procedureName, bool isRemote)
|
||||
public static bool LoadProcedure(ISession session, string procedureName, bool isRemote, IList<string> autoTests = null)
|
||||
{
|
||||
Procedure = null;
|
||||
|
||||
@ -556,13 +556,32 @@ namespace TBF.BenchControl
|
||||
.Where(x => (x.ProcedureState == ProcedureState.Active))
|
||||
.And(x => (x.Name == procedureName))
|
||||
.List();
|
||||
if (selectedProcs.Count == 1)
|
||||
{
|
||||
IsRemoteProcedure = isRemote;
|
||||
Procedure = selectedProcs[0];
|
||||
|
||||
if (selectedProcs.Count != 1) return false;
|
||||
Tests = selectedProcs[0].Tests;
|
||||
for (int i = Tests.Count - 1; i >= 0; i--)
|
||||
{
|
||||
Test test = Tests[i];
|
||||
if ((test.Name.Length > 0) && (test.Name[0] == '[') && test.Name.Contains("]"))
|
||||
{
|
||||
/// This is an AutoAction test => If 'actionName' is not on 'autoTests' list the test should be removed
|
||||
int actionNameEndPos = test.Name.IndexOf(']');
|
||||
string actionName = test.Name.Substring(1, actionNameEndPos - 1);
|
||||
if (autoTests == null || autoTests.Count == 0 || !autoTests.Contains(actionName))
|
||||
{
|
||||
/// AutoAction test was not selected and should be deleted
|
||||
Tests.RemoveAt(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Procedure = selectedProcs[0];
|
||||
Tests = selectedProcs[0].Tests;
|
||||
IsRemoteProcedure = isRemote;
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static void LoadProcedureParams(Procedure procedure)
|
||||
|
||||
@ -1111,6 +1111,7 @@
|
||||
<Compile Include="BenchControl\RegisterReaders\SerialStream\DatastreamFrame.cs" />
|
||||
<Compile Include="BenchControl\RegisterReaders\SerialStream\ProcParams.cs" />
|
||||
<Compile Include="BenchControl\Sequences\DeferredTestEvaluationData.cs" />
|
||||
<Compile Include="BenchControl\Sequences\MainSeqUtils.cs" />
|
||||
<Compile Include="BenchControl\Sequences\Plotter.cs" />
|
||||
<Compile Include="BenchControl\Sequences\Statistics.cs" />
|
||||
<Compile Include="BenchControl\Sequences\ProcessData.cs" />
|
||||
|
||||
Loading…
Reference in New Issue
Block a user