/// /// Copyright (c) 2013-2019 Sensus Slovensko a.s. /// using System; 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; namespace TBF.BenchControl.Sequences { public class MainSeq : SequenceBase { private static readonly ILog log = LogManager.GetLogger(typeof(MainSeq)); public override string ToString() { return "Sequences.MainSeq"; } bool benchFilled; int simultWithPurgingCount; Generic.IComponentCfg simultWithPurgingCfg; IList simultWithPurgingTests; IList simultWithPurgingParams; int simultWithEvacuationCount; Generic.IComponentCfg simultWithEvacuationCfg; IList simultWithEvacuationTests; IList simultWithEvacuationParams; System.Windows.Forms.Form modelessDlg; /// delegate void iPerlCommFormDlgt(MainSeq myRef, Generic.IComponentCfg cfg, IList tests, IList multiTestParams); /// void OpenIPerlCommForm(MainSeq myRef, Generic.IComponentCfg cfg, IList tests, IList multiTestParams) { try { /// 1nd argument TestMethods.iPerlCommunication.TestMethodCfg iPerlCfg = cfg as TestMethods.iPerlCommunication.TestMethodCfg; /// 2rd argument: as is /// 3th argument IList iPerlCommParams = new List(); foreach (var tp in multiTestParams) iPerlCommParams.Add(tp as TestMethods.iPerlCommunication.iPerlCommunicationParams); myRef.modelessDlg = new TestMethods.iPerlCommunication.iPerlCommunicationForm(iPerlCfg, tests, iPerlCommParams); myRef.modelessDlg.Show(); } catch (Exception e) { log.FatalFormat("---------------( MainSeq : OpenIperlCommForm crashed !!! )---------------"); log.FatalFormat("Message : {0}", e.Message); if (e.InnerException != null) { log.FatalFormat("InnerMessage : {0}", e.InnerException.Message); } log.FatalFormat("StackTrace : {0}{1}", Environment.NewLine, e.StackTrace); log.Fatal("--------------------------------------"); } } /// void CloseIPerlCommForm() { UiBridge.Bridge.OnCloseModelessForm(this, null); modelessDlg = null; } /// Constructor public MainSeq() { benchFilled = false; simultWithPurgingCount = 0; simultWithPurgingCfg = null; simultWithPurgingTests = new List(); simultWithPurgingParams = new List(); simultWithEvacuationCount = 0; simultWithEvacuationCfg = null; simultWithEvacuationTests = new List(); simultWithEvacuationParams = new List(); checkUiOp = new CheckUIOp(true); /// Running in almost all states } /// /// 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; } /// /// Main sequence /// /// /// public void Execute() { IList e = new List(); Selection selection; string selectedTestName; #if !DEBUG Bridge.OnActivity(this, Strings.Starting_system); WaitForOkButton(); SetValvesToDefaultState(); string scaleName; string message; if (TestCommunicationWithScales(out scaleName, out message) == false) { Bridge.OnError(this, string.Format("{0} : {1}", scaleName, message)); goto error; } if (!DrainTanks()) { Bridge.OnError(this, "Error when draining tanks"); goto error; } //-------------------------------------------------------------------------------------------- Bridge.OnActivity(this, Strings.Resetting_scales); Bridge.Bench2UI(ButtonsEtc.StopBtnEn); /// Resetting scales -> Enable STOP button DoubleBox tara1 = new DoubleBox(0); DoubleBox tara2 = new DoubleBox(0); DoubleBox tara3 = new DoubleBox(0); State.Create("MainSeq : Reset scales").AddOperation(checkUiOp) .AddOperation((StateMachine.Tank1 is IScale) ? (StateMachine.Tank1 as IScale).TaringOp(ref tara1) : null) .AddOperation((StateMachine.Tank2 is IScale) ? (StateMachine.Tank2 as IScale).TaringOp(ref tara2) : null) .AddOperation((StateMachine.Tank3 is IScale) ? (StateMachine.Tank3 as IScale).TaringOp(ref tara3) : null) .EnterState(); do { e = StateMachine.WaitRunDevsRunOps(); if (e.Contains(Event.Error)) goto error; if (e.Contains(Event.UiCmdStop)) goto stop; } while (e.Contains(Event.Busy)); //-------------------------------------------------------------------------------------------- Bridge.OnActivity(this, Strings.Measuring_the_weight); State.Create("MainSeq : Mesuring the weight for the 1st time") .AddOperation(checkUiOp) .AddOperation(new MettlerToledo.ReadMassesOp()) .EnterState(); do { e = StateMachine.WaitRunDevsRunOps(); if (e.Contains(Event.Error)) goto error; if (e.Contains(Event.UiCmdStop)) goto stop; } while (!e.Contains(Event.BalanceDone)); #endif select_procedure: CloseBeginForm(); /// Make sure the CycleBeginForm is closed (after an abnormal end, etc.) do { do { selection = MakeSelection(MKSelContext.ProcedureNotSelected); if (selection == Selection.Shutdown) { Shutdown(); return; } } while (selection == Selection.Shutdown); switch (selection) { case Selection.Q1: selectedTestName = "Q1"; break; case Selection.Q2: selectedTestName = "Q2"; break; case Selection.Q3: selectedTestName = "Q3"; break; default: selectedTestName = Bridge.SelectedTestName; break; } try { using (ISession localSession = Config.FluentCommon.CreateSession(Users.Entities.DBKind.Config)) { StateMachine.LoadPathsAndTransitions(localSession); } /// /// Try to load all parameters for the selected procedure from databases as specifie in BenchInfo /// if ((Bridge.SelectedProcedure != null) && !string.IsNullOrEmpty(Bridge.SelectedProcedure.Name)) { /// TODO: Repeate twice for Users.Entities.DBKind.Config and Users.Entities.DBKind.RemoteConfig using (ISession remoteOrLocalSession = Config.FluentCommon.CreateSession(Bridge.SelectedProcedure.DBKind)) { StateMachine.LoadProcedure(remoteOrLocalSession, Bridge.SelectedProcedure.Name); StateMachine.LoadProcedureParams(StateMachine.Procedure); /// This is to load Procedure.Tests and tets.MoreParams for each test int a = 0; foreach (var test in StateMachine.Procedure.Tests) a += test.MoreParams.Count; } } else { StateMachine.Procedure = null; } } catch (Exception) { StateMachine.Procedure = null; } } while (StateMachine.Procedure == null); /// Make sure a valid procedure is selected Debug.WriteLine(string.Empty); Debug.WriteLine(string.Format("TransitionSequences {0}", NHibernateUtil.IsInitialized(StateMachine.TransitionSequences) ? "initialized" : "NOT initialized")); Debug.WriteLine(string.Format("TransitionSteps {0}", NHibernateUtil.IsInitialized(StateMachine.TransitionSteps) ? "initialized" : "NOT initialized")); Debug.WriteLine(string.Format("Procedure {0}", NHibernateUtil.IsInitialized(StateMachine.Procedure) ? "initialized" : "NOT initialized")); Debug.WriteLine(string.Format("Procedure.MoreParams {0}", NHibernateUtil.IsInitialized(StateMachine.Procedure.MoreParams) ? "initialized" : "NOT initialized")); Debug.WriteLine(string.Format("Procedure.Tests {0}", NHibernateUtil.IsInitialized(StateMachine.Procedure.Tests) ? "initialized" : "NOT initialized")); if (StateMachine.Procedure.Tests.Count > 0) { Debug.WriteLine(string.Format("Procedure.Tests[0].MoreParams {0}", NHibernateUtil.IsInitialized(StateMachine.Procedure.Tests[0].MoreParams) ? "initialized" : "NOT initialized")); } UiBridge.Bridge.OnError(this, string.Empty); /// Clear an error message (if any) /// /// Procedure selected at this point, a new batch was started /// StateMachine.ControlBoard.ManualUIAllowed = !StateMachine.Procedure.ManualCtrlDisabled; Bridge.Bench2UI(ButtonsEtc.StopBtnEn); /// A new cycle started : Enable STOP button int newBatchNr = Program.LocalSettings.BatchNr; log.FatalFormat("New measurement session started: batch = {0}, procedure = {1}", newBatchNr, StateMachine.Procedure.Name); ClearSessionData(); if (selection == Selection.RestoreBatch) { BatchRslts = CreateNewBatchResults(newBatchNr, StateMachine.Procedure); RestoreBatchResults(TBF.UiBridge.Bridge.BatchNr, ref BatchRslts); /// pass the original batch number of the batch to be restored } else if (selection == Selection.RestoreAndFixBatch) { /// /// Restore and fix a batch - part 1 (fix "Previous workstep is missing" error) /// BatchRslts = CreateNewBatchResults(newBatchNr, StateMachine.Procedure); RestoreBatchResults(TBF.UiBridge.Bridge.BatchNr, ref BatchRslts); /// pass the original batch number of the batch to be restored for (int i = 0; i < BatchRslts.WaterMeters.Length; i++) { WaterMeter wm = BatchRslts.WaterMeters[i]; if (wm != null) { if (wm.Passed) { /// Water meter passed and was already saved to Oracle, do not reload & fix it now wm.Disabled = true; } else if (!wm.Disabled && Users.GlobalData.GetCurrentUserName() == "milan") { /// Water meter not passed and not disabled and user is 'milan' => reset flag E28 wm.ErrorFlags = wm.ErrorFlags & (~(int)ErrorFlagMask.E28); foreach (var mtr in wm.MeterTestRslts) { if (mtr.TestData().Evaluate && (mtr.TestData().Name == "Kontrola montaze") && (mtr.TestData().Method == "iPerlCommunication")) { mtr.TestDone = true; mtr.Passed = true; } } } } } } else { BatchRslts = CreateNewBatchResults(newBatchNr, StateMachine.Procedure); } StateMachine.CycleStartTimeStamp = BatchRslts.Batch.StartTime; Bridge.OnProcedureSelected(this, new ProcedureSelectedEventArgs(StateMachine.Procedure)); /// /// Display 'Cycle Begin Form' in case of a normal batch (not a restored batch) /// if ((selection != Selection.RestoreBatch) && (selection != Selection.RestoreAndFixBatch) && !OpenCycleBeginForm()) { goto stop; } /// /// Prepare operations for reading start info @ cycle start /// IList startInfoReadOps = new List(); string[] resultWriters = StateMachine.Procedure.ResultsWriter.Split(new char[] { '~' }); foreach (var writerName in resultWriters) { IStartInfoReader infoReader = TbfComponents.FindComponent(writerName) as IStartInfoReader; if (infoReader != null) { try { IOperation op = infoReader.ReadStartInfoOp(ProcessData.BatchRslts.WaterMeters); if (op != null) startInfoReadOps.Add(op); } catch (Exception exc) { Bridge.OnError(this, string.Format(Strings.Component_0_crashed_Results_not_saved, writerName)); log.FatalFormat("StartInfoReader {0} crashed: {1}", writerName, exc.Message); } } } /// /// Find purge suquences /// TransitionSequence purgeBegin = null; TransitionSequence purgeEnd = null; foreach (var transition in StateMachine.TransitionSequences) { if (transition.Name == StateMachine.Procedure.TransitionStart) purgeBegin = transition; if (transition.Name == StateMachine.Procedure.TransitionEnd) purgeEnd = transition; } if (selection == Selection.Q1 || selection == Selection.Q2 || selection == Selection.Q3 || selection == Selection.Test) { goto assume_bench_filled; } else if ((selection == Selection.Cycle && benchFilled) || (selection == Selection.RestoreBatch) || (selection == Selection.RestoreAndFixBatch)) { /// /// Always ask a question in case of a restored batch /// State.Create("MainSeq : Answer a question") .AddOperation(new Operations.AskYesNoOp(Strings.Fill_with_water)) .AddOperation(checkUiOp) .EnterState(); do { e = StateMachine.WaitRunDevsRunOps(); if (e.Contains(Event.No)) goto assume_bench_filled; if (e.Contains(Event.UiCmdStop)) goto select_procedure; } while (!e.Contains(Event.Yes)); } fill_the_bench: CollectSimultSteps(); /// if (simultWithPurgingCount > 0) { /// Make sure the entry form is closed if (UIFlowControl.Stop == WaitBeginFormClosed()) goto stop; /// Open iPerlCommunicationForm ProcessData.RegisterReaders = StateMachine.GetMetersPath(simultWithPurgingTests[0]).RegisterReaders; Program.MainWnd.Invoke(new iPerlCommFormDlgt(OpenIPerlCommForm), new object[] { this, simultWithPurgingCfg, simultWithPurgingTests, simultWithPurgingParams }); } /// /// Purging @ cycle start /// Event evt = Transition(purgeBegin, TransitionContext.PurgeBegin); switch (evt) { case Event.Error: if (simultWithPurgingCount > 0) CloseIPerlCommForm(); goto error; case Event.UiCmdStop: if (simultWithPurgingCount > 0) CloseIPerlCommForm(); goto stop; default: break; } /// /// Wait until iPerl communications or S/N data entry are completed /// if ((simultWithPurgingCount > 0) || (startInfoReadOps.Count > 0)) { /// Get 'bool completed' bool completed = !(modelessDlg is GenericDevices.IHasCompleted) || (modelessDlg as GenericDevices.IHasCompleted).Completed; if (lastDataEntryCmpnt != null) completed = completed && lastDataEntryCmpnt.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(); goto stop; } /// Update 'bool completed' completed = !(modelessDlg is GenericDevices.IHasCompleted) || (modelessDlg as GenericDevices.IHasCompleted).Completed; if (lastDataEntryCmpnt != null) completed = completed && lastDataEntryCmpnt.Completed; } while (!completed); } modelessDlg = null; } assume_bench_filled: benchFilled = true; Bridge.Bench2UI(ButtonsEtc.ShowBenchFilled); if ((selection == Selection.Cycle) || (selection == Selection.RestoreBatch) || (selection == Selection.RestoreAndFixBatch)) { /// /// Read start info from the DB @ cycle start /// if (startInfoReadOps.Count > 0) { State.Create("MainSeq : Reading start info from DB") .AddOperations(startInfoReadOps) .AddOperation(checkUiOp).EnterState(); do { e = StateMachine.WaitRunDevsRunOps(); if (e.Contains(Event.Error)) goto error; if (e.Contains(Event.UiCmdStop)) goto stop; } while (e.Contains(Event.Busy)); if (e.Contains(Event.InfoNotRead)) { log.ErrorFormat("StartInfoReader failed to read data from the database"); /// TODO: Message for an operator? Error? } else if ((selection == Selection.RestoreAndFixBatch) && (Users.GlobalData.GetCurrentUserName() != "milan")) { /// Restore and fix a batch - part 2 for (int i = 0; i < BatchRslts.WaterMeters.Length; i++) { WaterMeter wm = BatchRslts.WaterMeters[i]; if (wm != null && !wm.Disabled) { /// Water meter did not pass foreach (var mtr in wm.MeterTestRslts) { /// Find test entitled 'Kontrola montaze' if (mtr.TestData().Evaluate && (mtr.TestData().Name == "Kontrola montaze") && (mtr.TestData().Method == "iPerlCommunication")) { /// This meter test result (mtr) is 'Kontrola montaze' if (wm.LastRecordIsNok) { /// There is still a production tracing error, last record is missing wm.ErrorFlags |= (int)Config.Entities.ErrorFlagMask.E28; /// Set E28 } else { /// No production tracing error, last record is OK wm.ErrorFlags &= ~(int)Config.Entities.ErrorFlagMask.E28; /// Clear E28 } if ((wm.ErrorFlags & (int)Config.Entities.ErrorFlagMask.E28) != 0) { /// Previous workstep missing or NOK (production tracing error) mtr.ErrorIndicators |= (int)ErrorFlagMask.E28; mtr.Passed = false; } else { /// Previous step is OK mtr.Passed = true; } } } } } } /// Redraw on-screen results Bridge.OnTestCompleted(this, new TestCompletedEventArgs(string.Empty, null)); } } if ((selection != Selection.PurgeBegin) && (selection != Selection.RestoreBatch) && (selection != Selection.RestoreAndFixBatch)) { goto cycle_or_test_selected; } select_cycle_or_test: //---------------------------------------------------------- selection = MakeSelection(MKSelContext.InsideProcedure); if (selection == Selection.Shutdown) { Shutdown(); return; } switch (selection) { case Selection.Q1: selectedTestName = "Q1"; break; case Selection.Q2: selectedTestName = "Q2"; break; case Selection.Q3: selectedTestName = "Q3"; break; default: selectedTestName = Bridge.SelectedTestName; break; } /// UiBridge.Bridge.OnError(this, string.Empty); /// Clear an error message (if any) /// if (selection == Selection.PurgeBegin) goto fill_the_bench; if (selection == Selection.PurgeEnd) { switch (DoEvacuation(purgeEnd)) { case Event.Error: goto error; case Event.UiCmdStop: goto stop; default: goto select_cycle_or_test; } } if (selection == Selection.Break) { StateMachine.ControlBoard.ManualUIAllowed = true; Bridge.Bench2UI(ButtonsEtc.ShowBenchEmpty); Bridge.OnProcedureCompleted(this, new ProcedureCompletedEventArgs(StateMachine.Procedure)); goto select_procedure; } if (selection == Selection.SaveResults) goto save_results; cycle_or_test_selected: UiBridge.Bridge.OnError(this, string.Empty); /// Clear an error message (if any) if (UIFlowControl.Stop == WaitBeginFormClosed()) { goto stop_within_cycle; /// Make sure the entry form is closed } Bridge.Bench2UI(ButtonsEtc.StopBtnEn); /// Hide buttons if (selection != Selection.Cycle) { //-------------------------------- State.Create("MainSeq : Continue in the cycle?") .AddOperation(new Operations.AskYesNoOp(Strings.Continue_in_the_cycle)) .AddOperation(checkUiOp) .EnterState(); while (true) { e = StateMachine.WaitRunDevsRunOps(); if (e.Contains(Event.Yes)) { selection = Selection.RestOfCycle; break; } if (e.Contains(Event.No)) break; if (e.Contains(Event.UiCmdStop)) goto select_procedure; } } ///------------------------------------------------------------------------------------------------------------ if (selection == Selection.Cycle || selection == Selection.RestOfCycle) { /// A sequence of tests will be executed IList deferredData = new List(); bool veryFirstTestInTheRestOfCycle = true; int selsctedTestIx = simultWithPurgingCount; /// Applies when selection == Selection.Cycle int repetNr = 1; /// if (selection == Selection.RestOfCycle) /// ... otherwise { Test slctdTest = TBF.BenchControl.StateMachine.Procedure.GetTest(selectedTestName, out selsctedTestIx, out repetNr); if (slctdTest == null || (selsctedTestIx < simultWithPurgingCount) || (selsctedTestIx >= StateMachine.Tests.Count - simultWithEvacuationCount)) { /// Invalid test selection UiBridge.Bridge.OnError(this, string.Format("No test specified")); goto select_cycle_or_test; } } float TimeEstimateTotal = 0; /// Time estimate of the selected cycle or test for (int i = selsctedTestIx; i < StateMachine.Tests.Count - simultWithEvacuationCount; i++) { Test test = StateMachine.Tests[i]; TimeEstimateTotal += (test.Repeats * (test.TstTime + 10.0f)); /// Try to fetch all test paths and transitions /// to detect configuration errors as early as possible. TBF.BenchControl.Generic.IComponent testMethodComp = TbfComponents.FindComponent(test.Method); string errorMsg; if (!(testMethodComp is TBF.BenchControl.TestMethods.OuterLoop.Start.Component) && !(testMethodComp is TBF.BenchControl.TestMethods.OuterLoop.End.Component) && !StateMachine.GetPaths(test, (StateMachine.Procedure.MetersKind == MetersKind.HeatMeter), out inPath, out benchPath, out outPath, out sensPath, out heatMetersPath, out transitionBefore, out transitionBetween, out transitionAfter, out errorMsg)) { UiBridge.Bridge.OnError(this, errorMsg); goto select_cycle_or_test; } } int currentTestIx = selsctedTestIx; bool isOuterLoopMode = false; int outerLoopStartIx = -1; /// This is to identify program errors int outerLoopRepeats = 0; while (currentTestIx < StateMachine.Tests.Count - simultWithEvacuationCount) { Test nextTest = (currentTestIx + 1 < StateMachine.Tests.Count - simultWithEvacuationCount) ? StateMachine.Tests[currentTestIx + 1] : null; Test nextHydroTest = null; for (int i = currentTestIx + 1; i < StateMachine.Tests.Count - simultWithEvacuationCount; i++) { Test tst = StateMachine.Tests[i]; if (tst != null) { ITestMethod tm = TbfComponents.FindComponent(tst.Method) as ITestMethod; if (tm != null && tm.DoTransitions()) { nextHydroTest = tst; break; } } } if (nextHydroTest != null) { /// Fetch paths and 'transition before' of the next test TBF.BenchControl.Generic.IComponent nextTestMethodComp = TbfComponents.FindComponent(nextHydroTest.Method); TransitionSequence dummy2, dummy3; string errorMsg2; if (!(nextTestMethodComp is TBF.BenchControl.TestMethods.OuterLoop.Start.Component) && !(nextTestMethodComp is TBF.BenchControl.TestMethods.OuterLoop.End.Component) && !StateMachine.GetPaths(nextHydroTest, (StateMachine.Procedure.MetersKind == MetersKind.HeatMeter), out nextInPath, out nextBenchPath, out nextOutPath, out nextSensPath, out nextHeatMetersPath, out nextTransitionBefore, out dummy2, out dummy3, out errorMsg2)) { UiBridge.Bridge.OnError(this, errorMsg2); goto select_cycle_or_test; } nextQfrom = nextHydroTest.Qfrom; nextQto = nextHydroTest.Qto; nextPumpPower = nextHydroTest.PumpPower; nextTolerRed = nextHydroTest.TolerRed; nextPidCoef = (nextOutPath != null) ? nextOutPath.PidCoef : 1.0F; } else { /// Clear paths and 'transition before' of the next test it does not exist nextInPath = null; nextBenchPath = null; nextOutPath = null; nextSensPath = null; nextHeatMetersPath = null; nextTransitionBefore = null; } /// Fetch paths and transitions of this test Test test = StateMachine.Tests[currentTestIx]; TBF.BenchControl.Generic.IComponent testMethodComp = TbfComponents.FindComponent(test.Method); string errorMsg; if (!(testMethodComp is TBF.BenchControl.TestMethods.OuterLoop.Start.Component) && !(testMethodComp is TBF.BenchControl.TestMethods.OuterLoop.End.Component) && !StateMachine.GetPaths(test, (StateMachine.Procedure.MetersKind == MetersKind.HeatMeter), out inPath, out benchPath, out outPath, out sensPath, out heatMetersPath, out transitionBefore, out transitionBetween, out transitionAfter, out errorMsg)) { UiBridge.Bridge.OnError(this, errorMsg); goto select_cycle_or_test; } /// Update format for the water mass if (outPath != null && outPath.Scale != null && !string.IsNullOrEmpty(outPath.Scale.Format)) { Mass.Format = outPath.Scale.Format; StartMass.Format = outPath.Scale.Format; EndMass.Format = outPath.Scale.Format; } ITestMethod testMethod = testMethodComp as ITestMethod; if (testMethod != null && testMethod.CanTest(StateMachine.Procedure.MetersKind)) { if (isOuterLoopMode && (outerLoopRepeats != test.Repeats) && !(testMethod is TestMethods.OuterLoop.End.Component)) { goto config_error; } StateMachine.LoadTestParams(test); ProcessData.RegisterReaders = sensPath.RegisterReaders; foreach (var rr in sensPath.RegisterReaders) { if ((rr is TestMethods.iPerlCommunication.iPerlHead.IperlHead) && (BenchInfo != null)) { (rr as TestMethods.iPerlCommunication.iPerlHead.IperlHead).BenchName = BenchInfo.TestBenchName; } } /// /// Execute one test (single repetition of a repeated test) /// Previously: /// e = testMethod.Execute(test, outerLoopMode, (outerLoopMode ? outerLoopCounter: repetNr)); /// Event rsltTransBefore = Event.Done; Event rsltTransBetween = Event.Done; Event rsltTransAfter = Event.Done; { int timeEstTransBefore = testMethod.DoTransitions() ? GetTransitionTimeEst(transitionBefore) : 1; int timeEstTransBetween = testMethod.DoTransitions() ? GetTransitionTimeEst(transitionBetween) : 1; int timeEstTransAfter = testMethod.DoTransitions() ? GetTransitionTimeEst(transitionAfter) : 1; TestProgressEventArgs.SetEstimatedTimes(new int[] { 1, timeEstTransBefore, 1, 30, 0, Convert.ToInt32(test.TstTime) + 15, timeEstTransAfter, 0 }); Bridge.OnTestProgress(this, new TestProgressEventArgs(test, repetNr, Config.Entities.Progress.JustStarted)); bool currentTestFinished = true; bool doOneMoreRepetition = false; do { bool doExecuteTransitionBefore = isOuterLoopMode || (repetNr == 1) || veryFirstTestInTheRestOfCycle; veryFirstTestInTheRestOfCycle = false; if (testMethod.DoTransitions()) { /// Make a transition before a test and before each test repetition rsltTransBefore = Transition(doExecuteTransitionBefore ? transitionBefore : null, TransitionContext.BeforeTest); /// Transition or SetRoute - start of test log.InfoFormat("Test {0}: Transition({1}, BeforeTest) returned {2}", test.Name, (transitionBefore == null ? "null" : transitionBefore.Name), rsltTransBefore); } if (rsltTransBefore != Event.Done) break; log.InfoFormat("Test {0}: Execute(., {1}, {2})", test.Name, repetNr, isOuterLoopMode || repetNr == test.Repeats); e = testMethod.Execute(test, repetNr, isOuterLoopMode || repetNr == test.Repeats); if (e.Contains(Event.MakeSecondPass) && testMethod is ITestMethodWith2ndPass) { deferredData.Add(new DeferredTestEvaluationData(test, repetNr, (testMethod as ITestMethodWith2ndPass).IntermediateData)); } currentTestFinished = (rsltTransBefore == Event.Done && !e.Contains(Event.Error) && !e.Contains(Event.ConfigurationError) && !e.Contains(Event.OpArgumentError) && !e.Contains(Event.UiCmdStop)); Bridge.OnTestProgress(this, new TestProgressEventArgs(test, repetNr, currentTestFinished ? Config.Entities.Progress.Completed : Config.Entities.Progress.Aborted)); if (e.Contains(Event.OuterLoopStart)) break; /// Do not repeat OuterLoopStart test in this loop if (currentTestFinished && !isOuterLoopMode) repetNr++; doOneMoreRepetition = currentTestFinished && !isOuterLoopMode && (repetNr <= test.Repeats); if (testMethod.DoTransitions() && doOneMoreRepetition) { /// Make a transition between two test repetitions rsltTransBetween = Transition(transitionBetween, TransitionContext.BetweenTests); /// Transition or SetRoute - start of test log.InfoFormat("Test {0}: Transition({1}, BetweenTests) returned {2}", test.Name, (transitionBetween == null ? "null" : transitionBetween.Name), rsltTransBetween); } } while ((rsltTransBetween == Event.Done) && doOneMoreRepetition); if (currentTestFinished && !isOuterLoopMode && repetNr > test.Repeats) repetNr = 1; /// Reset repetNr if (testMethod.DoTransitions() && !e.Contains(Event.RecoverableError)) { /// Make a transition after the last test repetition TransitionContext endContext = !currentTestFinished ? TransitionContext.Stop : ((nextTransitionBefore != null) && (nextTransitionBefore.Name.ToLower().Contains("fastflow"))) ? TransitionContext.AfterTestWithOverlap : TransitionContext.AfterTest; rsltTransAfter = Transition(transitionAfter, endContext); /// Transition or SetRoute - end of test log.InfoFormat("Test {0}: Transition({1}, {2}) returned {3}", test.Name, (transitionAfter == null ? "null" : transitionAfter.Name), endContext, rsltTransAfter); } } if (rsltTransBefore == Event.Error || rsltTransBetween == Event.Error|| e.Contains(Event.Error)) { isOuterLoopMode = false; goto error; } else if (e.Contains(Event.ConfigurationError)) { isOuterLoopMode = false; goto select_cycle_or_test; /// OR goto config_error; ??? } else if (e.Contains(Event.OpArgumentError)) { isOuterLoopMode = false; goto config_error; } else if (rsltTransBefore == Event.UiCmdStop || e.Contains(Event.UiCmdStop) || e.Contains(Event.RecoverableError)) { isOuterLoopMode = false; goto stop_within_cycle; } else if (e.Contains(Event.OuterLoopStart)) { if (isOuterLoopMode) { goto config_error; } isOuterLoopMode = true; outerLoopRepeats = (nextTest != null) ? nextTest.Repeats : 1; repetNr = 1; outerLoopStartIx = currentTestIx; } else if (e.Contains(Event.OuterLoopEnd)) { if (!isOuterLoopMode) { goto config_error; } else if (++repetNr <= outerLoopRepeats) { currentTestIx = outerLoopStartIx; } else { isOuterLoopMode = false; repetNr = 1; /// Reset repetNr } } } else { UiBridge.Bridge.OnError(this, string.Format(Strings.Method_0_cannot_be_used, test.Method)); goto select_cycle_or_test; } currentTestIx++; } /// /// Execute deferred evaluations of tests that returned 'Event.MakeSecondPass' here /// foreach (var dfrrdData in deferredData) { string errorMsg; StateMachine.GetPaths(dfrrdData.Test, (StateMachine.Procedure.MetersKind == MetersKind.HeatMeter), out inPath, out benchPath, out outPath, out sensPath, out heatMetersPath, out transitionBefore, out transitionBetween, out transitionAfter, out errorMsg); ITestMethodWith2ndPass testMethod = TbfComponents.FindComponent(dfrrdData.Test.Method) as ITestMethodWith2ndPass; if (testMethod != null && testMethod.CanTest(StateMachine.Procedure.MetersKind)) { StateMachine.LoadTestParams(dfrrdData.Test); ProcessData.RegisterReaders = sensPath.RegisterReaders; foreach (var rr in sensPath.RegisterReaders) { if ((rr is TestMethods.iPerlCommunication.iPerlHead.IperlHead) && (BenchInfo != null)) { (rr as TestMethods.iPerlCommunication.iPerlHead.IperlHead).BenchName = BenchInfo.TestBenchName; } } e = testMethod.Execute2ndPass(dfrrdData.Test, dfrrdData.RepetNr, dfrrdData.IntermediateData); if (e.Contains(Event.Error)) goto error; else if (e.Contains(Event.OpArgumentError)) goto config_error; else if (e.Contains(Event.UiCmdStop)) goto stop_within_cycle; } } deferredData.Clear(); } ///------------------------------------------------------------------------------------------------------------ else { /// selection == Selection.Test or Selection.Q1 or Selection.Q2 or Selection.Q3 /// Single test will be executed int repetNr; int testIx; Test test = TBF.BenchControl.StateMachine.Procedure.GetTest(selectedTestName, out testIx, out repetNr); if (test == null) { UiBridge.Bridge.OnError(this, string.Format("No test specified")); goto select_cycle_or_test; } /// Fetch the test paths and transitions string errorMsg; TBF.BenchControl.Generic.IComponent testMethodComp = TbfComponents.FindComponent(test.Method); if (!(testMethodComp is TBF.BenchControl.TestMethods.OuterLoop.Start.Component) && !(testMethodComp is TBF.BenchControl.TestMethods.OuterLoop.End.Component) && !StateMachine.GetPaths(test, (StateMachine.Procedure.MetersKind == MetersKind.HeatMeter), out inPath, out benchPath, out outPath, out sensPath, out heatMetersPath, out transitionBefore, out transitionBetween, out transitionAfter, out errorMsg)) { UiBridge.Bridge.OnError(this, errorMsg); goto select_cycle_or_test; } /// Update format for the water mass Mass.Format = (outPath != null && outPath.Scale != null) ? outPath.Scale.Format : "F3"; StartMass.Format = (outPath != null && outPath.Scale != null) ? outPath.Scale.Format : "F3"; EndMass.Format = (outPath != null && outPath.Scale != null) ? outPath.Scale.Format : "F3"; ITestMethod testMethod = TbfComponents.FindComponent(test.Method) as ITestMethod; if (testMethod != null && testMethod.CanTest(StateMachine.Procedure.MetersKind)) { StateMachine.LoadTestParams(test); ProcessData.RegisterReaders = sensPath.RegisterReaders; foreach (var rr in sensPath.RegisterReaders) { if ((rr is TestMethods.iPerlCommunication.iPerlHead.IperlHead) && (BenchInfo != null)) { (rr as TestMethods.iPerlCommunication.iPerlHead.IperlHead).BenchName = BenchInfo.TestBenchName; } } Event rsltTransBefore = Event.Done; Event rsltTransAfter = Event.Done; { int timeEstTransBefore = testMethod.DoTransitions() ? GetTransitionTimeEst(transitionBefore) : 1; int timeEstTransBetween = testMethod.DoTransitions() ? GetTransitionTimeEst(transitionBetween) : 1; int timeEstTransAfter = testMethod.DoTransitions() ? GetTransitionTimeEst(transitionAfter) : 1; TestProgressEventArgs.SetEstimatedTimes(new int[] { 1, timeEstTransBefore, 1, 30, 0, Convert.ToInt32(test.TstTime) + 15, timeEstTransAfter, 0 }); /// start, transition, flow detection, flow setting, aborted, test, transition, end Bridge.OnTestProgress(this, new TestProgressEventArgs(test, repetNr, Config.Entities.Progress.JustStarted)); if (testMethod.DoTransitions()) { rsltTransBefore = Transition(transitionBefore, TransitionContext.BeforeTest); /// Transition or SetRoute - start of test } if (rsltTransBefore == Event.Done) { e = testMethod.Execute(test, repetNr, true); if (e.Contains(Event.MakeSecondPass) && testMethod is ITestMethodWith2ndPass) { ITestMethodWith2ndPass tm2 = testMethod as ITestMethodWith2ndPass; e = tm2.Execute2ndPass(test, repetNr, tm2.IntermediateData); } } bool testFinished = (rsltTransBefore == Event.Done && !e.Contains(Event.Error) && !e.Contains(Event.ConfigurationError) && !e.Contains(Event.OpArgumentError) && !e.Contains(Event.UiCmdStop)); Bridge.OnTestProgress(this, new TestProgressEventArgs(test, repetNr, testFinished ? Config.Entities.Progress.Completed : Config.Entities.Progress.Aborted)); if (testMethod.DoTransitions()) { TransitionContext endContext = testFinished ? TransitionContext.AfterTest : TransitionContext.Stop; rsltTransAfter = Transition(transitionAfter, endContext); /// Transition or SetRoute - end of test } Bridge.OnTestProgress(this, new TestProgressEventArgs(test, repetNr, testFinished ? Config.Entities.Progress.Completed : Config.Entities.Progress.Aborted)); } if (rsltTransBefore == Event.Error || e.Contains(Event.Error)) goto error; if (e.Contains(Event.ConfigurationError)) goto config_error; if (e.Contains(Event.OpArgumentError)) goto config_error; if (rsltTransBefore == Event.UiCmdStop || e.Contains(Event.UiCmdStop)) goto stop_within_cycle; } else { UiBridge.Bridge.OnError(this, string.Format("{0} cannot be used", test.Method)); goto select_cycle_or_test; } } ///------------------------------------------------------------------------------------------------------------ goto select_cycle_or_test; save_results: UiBridge.Bridge.OnError(this, string.Empty); /// Clear an error message (if any) Bridge.Bench2UI(ButtonsEtc.StopBtnEn); /// Hide most of buttons if (State.LastEvents.Contains(Event.ModelessFormIsOpen)) { if (UIFlowControl.Stop == WaitBeginFormClosed()) goto stop; } else if (State.LastEvents.Contains(Event.ModelessFormClosed)) { CloseBeginForm(); } Bridge.OnActivity(this, Strings.Enter_protocol_data); //-------------------------------- GenericDevices.IDataEntry dataEntryCmpnt = TbfComponents.FindComponent(StateMachine.Procedure.DataEntry) as GenericDevices.IDataEntry; if (dataEntryCmpnt != null) { if (dataEntryCmpnt is IHasCycleEndForm) { /// Open the modeless form for the end of the cycle State.Create("MainSeq : Enter end data") .AddOperation((dataEntryCmpnt as GenericDevices.IHasCycleEndForm).ShowCycleEndFormOp()) .AddOperation(checkUiOp) .EnterState(); do { e = StateMachine.WaitRunDevsRunOps(); if (e.Contains(Event.UiCmdStop)) goto stop; } while (!e.Contains(Event.ModelessFormClosed)); } dataEntryCmpnt.UpdateTestResults(BatchRslts); } if (TBF.BenchControl.Sequences.ProcessData.BatchRslts != null && Program.LocalSettings != null) { Results.Utils.GetCounterStates(ProcessData.BatchRslts.Batch, Program.LocalSettings.Counters); } ProcessData.BatchRslts.Batch.EndTime = DateTime.Now; ProcessData.BatchRslts.AddWaterMetersToBatch(); //------------------------------------------------------ Bridge.OnActivity(this, Strings.Saving_and_printing_results); State savingAndPrintingRslts = State.Create("MainSeq : Saving and printing results"); string[] writers = StateMachine.Procedure.ResultsWriter.Split(new char[] { '~' }); foreach (var writerName in writers) { IResultsWriter writer = TbfComponents.FindComponent(writerName) as IResultsWriter; if (writer != null) { try { savingAndPrintingRslts.AddOperation(writer.WriteResultsOp(ProcessData.BatchRslts.Batch)); } catch (Exception exc) { Bridge.OnError(this, string.Format(Strings.Component_0_crashed_Results_not_saved, writerName)); log.FatalFormat("FileWriter {0} crashed: {1}", writerName, exc.Message); } } } string[] printers = StateMachine.Procedure.ResultsPrinter.Split(new char[] { '~' }); foreach (var printerName in printers) { IResultsPrinter printer = TbfComponents.FindComponent(printerName) as IResultsPrinter; if (printer != null && !printer.SupressPrinting) { try { savingAndPrintingRslts.AddOperation(printer.PrintResultsOp(ProcessData.BatchRslts.Batch)); } catch (Exception exc) { Bridge.OnError(this, string.Format(Strings.Component_0_crashed_Results_not_printed, printerName)); log.FatalFormat("Printer {0} crashed: {1}", printerName, exc.Message); } } } savingAndPrintingRslts.AddOperation(checkUiOp).EnterState(); do { e = StateMachine.WaitRunDevsRunOps(); if (e.Contains(Event.Error)) goto error; if (e.Contains(Event.UiCmdStop)) goto stop; } while (e.Contains(Event.Busy)); bool resultsSent = !e.Contains(Event.ResultsNotWritten); ProcessData.BatchRslts.Batch.RsltsSent = resultsSent; /// /// Save results to 'Results' MySQL database /// Results.DB.SaveNewBatch(ProcessData.BatchRslts.Batch); /// /// Save results to 'summary results' logger /// foreach (var tr in ProcessData.BatchRslts.Batch.TestRslts) { summaryResults.Info(TestResult2CsvLine(tr)); } Program.LocalSettings.BatchNr++; Program.LocalSettings.Save(); log.FatalFormat("Measurement session saved: batch = {0}, procedure = {1}, next batch nr. = {2}", ProcessData.BatchRslts.Batch.BatchNr, ProcessData.BatchRslts.Batch.ProcedureName, Program.LocalSettings.BatchNr); evacuation: /// Evacuation is similar to 'Abort session' (no results are saved), but the evacuation is done as well. StateMachine.ControlBoard.ManualUIAllowed = true; Event evacRetv = DoEvacuation(purgeEnd); Bridge.OnProcedureCompleted(this, new ProcedureCompletedEventArgs(StateMachine.Procedure)); switch (evacRetv) { case Event.Error: goto error; case Event.UiCmdStop: goto stop; default: goto select_procedure; } stop_within_cycle: //-------------------------------- State.Create("MainSeq : Turning IDLE -> Closing the valves") .AddOperation(checkUiOp) .AddOperation(StateMachine.ControlBoard.SetValvesOp(StateMachine.DefaultValvesOpen, StateMachine.DefaultValvesClose)) .EnterState(); do { e = StateMachine.WaitRunDevsRunOps(); if (e.Contains(Event.Error)) goto error; } while (!e.Contains(Event.ValvesSet)); goto select_cycle_or_test; stop: //-------------------------------- State.Create("MainSeq : Turning IDLE -> Closing the valves") .AddOperation(checkUiOp) .AddOperation(StateMachine.ControlBoard.SetValvesOp(StateMachine.DefaultValvesOpen, StateMachine.DefaultValvesClose)) .EnterState(); do { e = StateMachine.WaitRunDevsRunOps(); if (e.Contains(Event.Error)) goto error; } while (!e.Contains(Event.ValvesSet)); goto select_procedure; config_error: //-------------------------------- State.Create("MainSeq : Procedure configuration error") .AddOperation(checkUiOp) .AddOperation(StateMachine.BenchErrorOp) .AddOperation(new Operations.MessageBoxOp("Test configration error")) .EnterState(); do { e = StateMachine.WaitRunDevsRunOps(); } while (!e.Contains(Event.OK)); goto select_cycle_or_test; error: //-------------------------------- State.Create("MainSeq : ERROR -> Closing the valves") .AddOperation(checkUiOp) .AddOperation(StateMachine.BenchErrorOp) .AddOperation(StateMachine.ControlBoard.SetValvesOp(StateMachine.DefaultValvesOpen, StateMachine.DefaultValvesClose)) .EnterState(); do { e = StateMachine.WaitRunDevsRunOps(); } while (!e.Contains(Event.ValvesSet) && !e.Contains(Event.Error)); //-------------------------------- State.Create("MainSeq : ERROR state") .AddOperation(checkUiOp) .AddOperation(StateMachine.BenchErrorOp) .EnterState(); do { e = StateMachine.WaitRunDevsRunOps(); } while (!e.Contains(Event.UiCmdShutdown)); Shutdown(true); return; } /// /// MakeSelection() call context /// enum MKSelContext { ProcedureNotSelected, InsideProcedure, } /// /// Return values of MakeSelection() /// public enum Selection { PurgeBegin, PurgeEnd, Break, Cycle, RestOfCycle, Test, Q1, Q2, Q3, SaveResults, RestoreBatch, RestoreAndFixBatch, Shutdown, } /// /// 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); /// 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) | (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 (e.Contains(Event.UiCmdBreak) && (context == MKSelContext.InsideProcedure)) 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; } 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.WaterMeters.Length; i++) { WaterMeter wm = batchResults.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; } } }