/// /// Copyright (c) 2013-2021 Sensus Slovensko a.s. /// using System; using System.Collections.Generic; using System.Diagnostics; using log4net; using NHibernate; using Config.Entities; using Results.Entities; using TBF.BenchControl.Operations; using TBF.BenchControl.GenericDevices; using TBF.Boxes; using TBF.Resources; using TBF.UiBridge; namespace TBF.BenchControl.Sequences { public partial 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 } /// /// Main sequence execution /// public void Execute() { IList e = new List(); Selection selection; string selectedTestName; 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 State.Create("MainSeq : Reset scales").AddOperation(checkUiOp) .AddOperation((StateMachine.Tank1 is IScale) ? (StateMachine.Tank1 as IScale).ZeroOp() : null) .AddOperation((StateMachine.Tank2 is IScale) ? (StateMachine.Tank2 as IScale).ZeroOp() : null) .AddOperation((StateMachine.Tank3 is IScale) ? (StateMachine.Tank3 as IScale).ZeroOp() : 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)); 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); selectedTestName = (selection == Selection.Q1) ? "Q1" : ((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; /// if (selection == Selection.RestoreInterruptedSession) { int batchNr; string version; processDataHeaderOK = ProcessData.LoadProcessDataHeader(out batchNr, out version, out interruptedProcedureName, out isRemoteIntProc); if (!processDataHeaderOK) { UiBridge.Bridge.OnError(this, "Invalid process data"); continue; } else if (version != Program.Version) { /// Program version does not match the one stored in process data UiBridge.Bridge.OnError(this, Strings.Program_version_does_not_match); continue; } else if (batchNr != Program.LocalSettings.BatchNr) { /// Program version does not match the one stored in process data UiBridge.Bridge.OnError(this, Strings.Invalid_batch_number); continue; } restoreInterruptedSession = true; } try { using (ISession localSession = Config.FluentCommon.CreateSession(Users.Entities.DBKind.Config)) { StateMachine.LoadPathsAndTransitions(localSession); } /// /// Try to load all parameters of selected or restored procedure from the respective database /// 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 : Users.Entities.DBKind.Config)) { StateMachine.LoadProcedure(remoteOrLocalSession, interruptedProcedureName, isRemoteIntProc); StateMachine.LoadProcedureParams(StateMachine.Procedure); /// 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, testsInside); StateMachine.LoadProcedureParams(StateMachine.Procedure); /// 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 { 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) if (selection == Selection.RestoreInterruptedSession) { if (!LoadProcessData()) { /// Restorig interrupted session failed UiBridge.Bridge.OnError(this, "Restorig interrupted session failed"); goto stop; } } else { /// Clear session data in case this is not an interrupted/restored session ClearSessionData(); } /// /// Procedure selected at this point, a new batch was started /// int newBatchNr = Program.LocalSettings.BatchNr; StateMachine.ControlBoard.ManualUIAllowed = !StateMachine.Procedure.ManualCtrlDisabled; Bridge.Bench2UI(ButtonsEtc.StopBtnEn); /// A new cycle started : Enable STOP button log.FatalFormat("New measurement session started: batch = {0}, procedure = {1}", newBatchNr, StateMachine.Procedure.Name); 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.Batch.WaterMeters.Count; i++) { WaterMeter wm = BatchRslts.Batch.WaterMeters[i]; if (wm != null && !wm.Disabled) { if (wm.Passed) { /// Water meter passed and was already saved to Oracle, do not reload & fix it now wm.Disabled = true; } else if ((wm.ErrorFlags & (int)ErrorFlagMask.E28) == 0) { /// Water meter failed but the failure is not an assembly error wm.Disabled = true; } else if (!wm.Disabled && (Users.GlobalData.GetCurrentUserName() == "milan" || Users.GlobalData.GetCurrentUserName() == "augustin" || Users.GlobalData.GetCurrentUserName() == "michal" || Users.GlobalData.GetCurrentUserName() == "michal2")) { /// Water meter failed, is not disabled, there is an assembly error and user is one of above /// ... => 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 if (selection != Selection.RestoreInterruptedSession) { /// This is a regular session => initialize BatchRslts BatchRslts = CreateNewBatchResults(newBatchNr, StateMachine.Procedure); } BatchRslts.Batch.IsRemoteProcedure = StateMachine.IsRemoteProcedure; StateMachine.CycleStartTimeStamp = BatchRslts.Batch.StartTime; Bridge.OnProcedureSelected(this, new ProcedureSelectedEventArgs(StateMachine.Procedure)); /// Select procedure in case of interrupted session if (selection != Selection.RestoreBatch && selection != Selection.RestoreAndFixBatch && selection != Selection.RestoreInterruptedSession) { /// /// This is a normal batch (not a restored one) => Display 'Cycle Begin Form' /// if (!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.Batch.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 || selection == Selection.RestoreInterruptedSession) { goto assume_bench_filled; } else if ((selection == Selection.Cycle && benchFilled) || (selection == Selection.RestoreBatch) || (selection == Selection.RestoreAndFixBatch) || (selection == Selection.RestoreInterruptedSession)) { /// /// 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.Batch.WaterMeters.Count; i++) { WaterMeter wm = BatchRslts.Batch.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.Cycle || selection == Selection.RestOfCycle || selection == Selection.Test || selection == Selection.Q1 || selection == Selection.Q2 || selection == Selection.Q3) { goto cycle_or_test_selected; } else if (selection == Selection.RestoreInterruptedSession) { /// Make progress bars of completed test green foreach (var testRslt in BatchRslts.Batch.TestRslts) { Bridge.OnTestProgress(this, new TestProgressEventArgs(testRslt)); } /// TODO: Try to find out where the cycle stopped } else { /// Do nothing } 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 = -1; ///= undefined /// if (selection == Selection.RestOfCycle) /// ... otherwise { for (int i = 0; i < StateMachine.TestInstances.Length; i++) { if (selectedTestName == StateMachine.TestInstances[i].Name) { selsctedTestIx = i; break; } } if ((selsctedTestIx < simultWithPurgingCount) || (selsctedTestIx >= StateMachine.TestInstances.Length - simultWithEvacuationCount)) { /// Invalid test selection UiBridge.Bridge.OnError(this, string.Format("No test specified")); goto select_cycle_or_test; } } else { selsctedTestIx = simultWithPurgingCount; /// Applies when selection == Selection.Cycle } float TimeEstimateTotal = 0; /// Time estimate of the selected cycle or test for (int i = selsctedTestIx; i < StateMachine.TestInstances.Length - simultWithEvacuationCount; i++) { Test test = StateMachine.TestInstances[i].Test; TimeEstimateTotal += (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; while (currentTestIx < StateMachine.TestInstances.Length - simultWithEvacuationCount) { TestInstance nextTest = (currentTestIx + 1 < StateMachine.TestInstances.Length - simultWithEvacuationCount) ? StateMachine.TestInstances[currentTestIx + 1] : null; Test nextHydroTest = null; for (int i = currentTestIx + 1; i < StateMachine.TestInstances.Length - simultWithEvacuationCount; i++) { Test tst = StateMachine.TestInstances[i].Test; 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 TestInstance testInst = StateMachine.TestInstances[currentTestIx]; TBF.BenchControl.Generic.IComponent testMethodComp = TbfComponents.FindComponent(testInst.Test.Method); string errorMsg; if (!StateMachine.GetPaths(testInst.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)) { StateMachine.LoadTestParams(testInst.Test); if ((sensPath != null) && (sensPath.RegisterReaders != null)) { 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; } } } else { ProcessData.RegisterReaders = null; } /// /// 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(testInst.Test.TstTime) + 15, timeEstTransAfter, 0 }); Bridge.OnTestProgress(this, new TestProgressEventArgs(testInst.Test, testInst.Repetition, Config.Entities.Progress.JustStarted)); bool currentTestFinished = true; bool doOneMoreRepetition = false; bool doExecuteTransitionBefore = (currentTestIx == simultWithPurgingCount) || (testInst.Test != StateMachine.TestInstances[currentTestIx - 1].Test) || veryFirstTestInTheRestOfCycle; bool isLastRepetition = (currentTestIx == StateMachine.TestInstances.Length - simultWithEvacuationCount - 1) || (testInst.Test != StateMachine.TestInstances[currentTestIx + 1].Test); 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}", testInst.Name, (transitionBefore == null ? "null" : transitionBefore.Name), rsltTransBefore); } if (rsltTransBefore != Event.Done) break; log.InfoFormat("Test {0}: Execute(., {1}, {2})", testInst.Name, testInst.Repetition, isLastRepetition); e = testMethod.Execute(testInst.Test, testInst.Repetition, isLastRepetition); if (e.Contains(Event.MakeSecondPass) && testMethod is ITestMethodWith2ndPass) { deferredData.Add(new DeferredTestEvaluationData(testInst.Test, testInst.Repetition, (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(testInst.Test, testInst.Repetition, currentTestFinished ? Config.Entities.Progress.Completed : Config.Entities.Progress.Aborted)); if (testMethod.DoTransitions() && !e.Contains(Event.RecoverableError)) { if (currentTestFinished && !isLastRepetition && !e.Contains(Event.ErrorFlagsStop)) { /// 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}", testInst.Name, (transitionBetween == null ? "null" : transitionBetween.Name), rsltTransBetween); } else { /// 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}", testInst.Name, (transitionAfter == null ? "null" : transitionAfter.Name), endContext, rsltTransAfter); } } } if (rsltTransBefore == Event.Error || rsltTransBetween == Event.Error|| e.Contains(Event.Error)) { goto error; } else if (e.Contains(Event.ConfigurationError)) { goto select_cycle_or_test; /// OR goto config_error; ??? } else if (e.Contains(Event.OpArgumentError)) { goto config_error; } else if (rsltTransBefore == Event.UiCmdStop || e.Contains(Event.UiCmdStop) || e.Contains(Event.RecoverableError) || e.Contains(Event.ErrorFlagsStop)) { goto stop_within_cycle; } } else { UiBridge.Bridge.OnError(this, string.Format(Strings.Method_0_cannot_be_used, testInst.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); if ((sensPath != null) && (sensPath.RegisterReaders != null)) { 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; } } } else { ProcessData.RegisterReaders = null; } 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 testIx = -1; ///= undefined /// for (int i = 0; i < StateMachine.TestInstances.Length; i++) { if (selectedTestName == StateMachine.TestInstances[i].Name) { testIx = i; break; } } if (testIx < 0) { /// Invalid test selection UiBridge.Bridge.OnError(this, string.Format("No test specified")); goto select_cycle_or_test; } Test test = StateMachine.TestInstances[testIx].Test; int repetNr = StateMachine.TestInstances[testIx].Repetition; /// 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); if ((sensPath != null) && (sensPath.RegisterReaders != null)) { 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; } } } else { ProcessData.RegisterReaders = null; } 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 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)); } /// /// Update batch results, determine whether watermeters passed all required tests /// BatchRslts.Batch.EndTime = DateTime.Now; /// Set cycle end time Results.Utils.GetCounterStates(BatchRslts.Batch, Program.LocalSettings.Counters); /// Update counters /// Remove results of internal tests for (int i = BatchRslts.Batch.TestRslts.Count - 1; i >= 0; i--) { foreach (var wm in BatchRslts.Batch.WaterMeters) { for (int j = wm.MeterTestRslts.Count - 1; j >= 0; j--) { MeterTestRslt mtr = wm.MeterTestRslts[j]; if ((mtr.Publish() == Publish.Never || mtr.Publish() == Publish.Internal) && !mtr.Evaluate()) { wm.MeterTestRslts.RemoveAt(j); } } } TestRslt tr = BatchRslts.Batch.TestRslts[i]; if ((tr.Publish() == Publish.Never || tr.Publish() == Publish.Internal) && !tr.Evaluate()) { BatchRslts.Batch.TestRslts.RemoveAt(i); } } /// (1) Set boolean WaterMeter.Passed variable, (2) Remove disabled water meters for (int wmNr0 = ProcessData.BatchRslts.Batch.WaterMeters.Count - 1; wmNr0 >= 0; wmNr0--) { WaterMeter wm = ProcessData.BatchRslts.Batch.WaterMeters[wmNr0]; if (wm.Disabled) { /// Do not save disabled watermeters to DB, remove them from the list ProcessData.BatchRslts.Batch.WaterMeters.RemoveAt(wmNr0); } else { /// Determine whether the watermeter passed all required tests wm.Passed = wm.PassedFromTests(); } } //------------------------------------------------------ Bridge.OnActivity(this, Strings.Saving_and_printing_results); //------------------------------------------------------ string[] writers = (StateMachine.Procedure.ResultsWriter != null) ? StateMachine.Procedure.ResultsWriter.Split(new char[] { '~' }) : new string[0]; string[] printers = (StateMachine.Procedure.ResultsPrinter != null) ? StateMachine.Procedure.ResultsPrinter.Split(new char[] { '~' }) : new string[0]; string[] eventTriggers = (StateMachine.Procedure.EventTriggers != null) ? StateMachine.Procedure.EventTriggers.Split(new char[] { '~' }) : new string[0]; /// string[] rsltProcessors = new string[writers.Length + printers.Length + eventTriggers.Length]; writers.CopyTo(rsltProcessors, 0); printers.CopyTo(rsltProcessors, writers.Length); eventTriggers.CopyTo(rsltProcessors, writers.Length + printers.Length); /// State savingAndPrintingRslts = State.Create("MainSeq : Saving and printing results"); foreach (var rpName in rsltProcessors) { IResultsProcessor rsltProcessor = TbfComponents.FindComponent(rpName) as IResultsProcessor; if (rsltProcessor != null) { try { savingAndPrintingRslts.AddOperation(rsltProcessor.ProcessResultsOp(ProcessData.BatchRslts.Batch)); } catch (Exception exc) { Bridge.OnError(this, string.Format(Strings.Component_0_crashed_Results_not_saved, rpName)); log.FatalFormat("FileWriter {0} crashed: {1}", rpName, 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.ErrorProcessingResults); ProcessData.BatchRslts.Batch.RsltsSent = resultsSent; /// /// Save results to 'Results' MySQL database /// Results.DB.SaveNewBatch(ProcessData.BatchRslts.Batch); /// /// Save results to 'summary results' logger /// log.WarnFormat("Saving SummaryResults of batch {0}", ProcessData.BatchRslts.Batch.BatchNr); foreach (var tr in ProcessData.BatchRslts.Batch.TestRslts) { summaryResults.Info(TestResult2CsvLine(tr)); } /// /// Clear a file with interim test results /// ClearProcessData(); 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); StateMachine.ControlBoard.ManualUIAllowed = true; Event evacRetv = DoEvacuation(purgeEnd); /// /// Process statistics (in each regular cycle after evacuation when ProcessData.StatisticsMonitoringComp is defined) /// if (ProcessData.StatisticsMonitoringComp is IStatisticsMonitoring) { State.Create("MainSeq : Processing statistics") .AddOperation((ProcessData.StatisticsMonitoringComp as IStatisticsMonitoring).ProcessStatisticsOp(ProcessData.BatchRslts.Batch.BatchNr)) .AddOperation(checkUiOp) .EnterState(); do { e = StateMachine.WaitRunDevsRunOps(); if (e.Contains(Event.UiCmdStop)) goto stop; } while (e.Contains(Event.Busy)); } /// /// Procedure completed, branch depending on the result of evacuation /// 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 configuration 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, RestoreInterruptedSession, } } }