diff --git a/TBF/BenchControl/Sequences/MainSeq.cs b/TBF/BenchControl/Sequences/MainSeq.cs index 0dbbfb828..339837d68 100644 --- a/TBF/BenchControl/Sequences/MainSeq.cs +++ b/TBF/BenchControl/Sequences/MainSeq.cs @@ -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 - /// Constructor + /// + /// Constructor + /// public MainSeq() { benchFilled = false; @@ -99,268 +98,8 @@ namespace TBF.BenchControl.Sequences /// - /// Unconditionally wait for OK button + /// Main sequence execution /// - 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)) { } - } - - - /// - /// Unconditionally set valves to default position - /// - 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)) { } - } - - - /// - /// Test communication with all scales that support S/N read operation - /// - /// Name of a scale that failed - /// Message in case of a failure - /// true = Test passed, all scales communicate OK - 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 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; - } - - - /// - /// - /// - /// true = OK, false = error - bool DrainTanks() - { - IList 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 fullDrainValves = new List(); - IList secondHalfDrainValves = new List(); - IList allDrainValves = new List(); - 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 - } - - - /// - /// This function is called after a procedure was selected and all components procedure parameters of components were loaded - /// - 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; - } - - - /// - /// Main sequence - /// - /// - /// public void Execute() { IList e = new List(); @@ -446,10 +185,17 @@ namespace TBF.BenchControl.Sequences : ((selection == Selection.Q2) ? "Q2" : ((selection == Selection.Q3) ? "Q3" : Bridge.SelectedTestName)); + /// + /// Auto invocation actions + /// + IList procedureBefore = new List(); + IList testsInside = new List(); + IList procedureAfer = new List(); /// /// 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, } - - - /// - /// Idle loop to make a procedure or test selection. - /// Handles tank emptying, camera test. - /// - /// Context where MakeSelection() is called - /// - /// Selection.PurgeBegin, PurgeEnd, Break, Cycle, Test, Q1, Q2, Q3 or SaveResults - /// - 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 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 openValves = new List(); - IList closeValves = new List(); - - 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 drainValves = new List(); - 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 - } - - /// - /// Create a new empty batch results from the procedure - /// - /// New batch number - /// Selected procedure - /// Created BatchResults - 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())); - } - - - /// - /// Reload batch results from Results database given the batch number - /// - /// Original batch number - /// New unique batch number - /// Reloaded procedure - /// - 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++; - } - } - - - /// - /// Executes steps of a evacuation sequence - /// - /// - /// 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) - /// - Event DoEvacuation(TransitionSequence purgeEnd) - { - IList 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; - } } } diff --git a/TBF/BenchControl/Sequences/MainSeqUtils.cs b/TBF/BenchControl/Sequences/MainSeqUtils.cs new file mode 100644 index 000000000..b7ee7cfcd --- /dev/null +++ b/TBF/BenchControl/Sequences/MainSeqUtils.cs @@ -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 + { + /// + /// Wrapper + /// + IList ServeCalendarEventsInvokeXY(Config.CalendarEvent.AutoAction selectedAction, int maxCount = 1) + { + return TBF.UI.Calendar.CalendarTabPageCtrl.ServeCalendarEventsInvokeXY(selectedAction, maxCount); + } + + /// + /// Unconditionally wait for OK button + /// + 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)) { } + } + + /// + /// Unconditionally set valves to default position + /// + 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)) { } + } + + /// + /// Test communication with all scales that support S/N read operation + /// + /// Name of a scale that failed + /// Message in case of a failure + /// true = Test passed, all scales communicate OK + 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 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; + } + + /// + /// + /// + /// true = OK, false = error + bool DrainTanks() + { + IList 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 fullDrainValves = new List(); + IList secondHalfDrainValves = new List(); + IList allDrainValves = new List(); + 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 + } + + /// + /// This function is called after a procedure was selected and all components procedure parameters of components were loaded + /// + 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; + } + + /// + /// Idle loop to make a procedure or test selection. + /// Handles tank emptying, camera test. + /// + /// Context where MakeSelection() is called + /// + /// Selection.PurgeBegin, PurgeEnd, Break, Cycle, Test, Q1, Q2, Q3 or SaveResults + /// + 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 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 openValves = new List(); + IList closeValves = new List(); + + 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 drainValves = new List(); + 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 + } + + /// + /// Create a new empty batch results from the procedure + /// + /// New batch number + /// Selected procedure + /// Created BatchResults + 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())); + } + + /// + /// Reload batch results from Results database given the batch number + /// + /// Original batch number + /// New unique batch number + /// Reloaded procedure + /// + 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++; + } + } + + /// + /// Executes steps of a evacuation sequence + /// + /// + /// 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) + /// + Event DoEvacuation(TransitionSequence purgeEnd) + { + IList 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; + } + } +} diff --git a/TBF/BenchControl/StateMachine.cs b/TBF/BenchControl/StateMachine.cs index f345aeb25..4f3db327c 100644 --- a/TBF/BenchControl/StateMachine.cs +++ b/TBF/BenchControl/StateMachine.cs @@ -548,7 +548,7 @@ namespace TBF.BenchControl /// Loads selected procedure from the DB. /// Updates StateMachine.Procedure and StateMachine.Tests /// - public static bool LoadProcedure(ISession session, string procedureName, bool isRemote) + public static bool LoadProcedure(ISession session, string procedureName, bool isRemote, IList 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) diff --git a/TBF/TBF.csproj b/TBF/TBF.csproj index 769e22758..7775d2363 100644 --- a/TBF/TBF.csproj +++ b/TBF/TBF.csproj @@ -1111,6 +1111,7 @@ +