From d5cb6ca71bd2416dc71882bf4adeead66cb6c9ad Mon Sep 17 00:00:00 2001 From: Milan Hanajik Date: Fri, 4 Sep 2015 13:49:04 +0200 Subject: [PATCH] iPerlCommunication simultaneously with purging, STOP button function fixed, version 1.5.106 --- .../GenericDevices/ISimultTestMethod.cs | 22 ++ .../BenchControl/Sequences/MainSeq.cs | 166 +++++++-- .../BenchControl/StateMachine.cs | 45 ++- .../iPerlCommunication/TestMethod.cs | 4 +- .../iPerlCommunication/TestMethodCfg.cs | 1 - .../iPerlCommunicationForm.cs | 337 ++++++++++-------- .../iPerlCommunicationForm.designer.cs | 1 - .../iPerlCommunicationParams.cs | 20 +- .../iPerlCommunicationSeq.cs | 76 ++-- TestBenchFramework/Properties/AssemblyInfo.cs | 4 +- .../Resources/Strings.Designer.cs | 27 ++ TestBenchFramework/Resources/Strings.resx | 9 + TestBenchFramework/TBF.csproj | 1 + 13 files changed, 474 insertions(+), 239 deletions(-) create mode 100644 TestBenchFramework/BenchControl/GenericDevices/ISimultTestMethod.cs diff --git a/TestBenchFramework/BenchControl/GenericDevices/ISimultTestMethod.cs b/TestBenchFramework/BenchControl/GenericDevices/ISimultTestMethod.cs new file mode 100644 index 000000000..74a209139 --- /dev/null +++ b/TestBenchFramework/BenchControl/GenericDevices/ISimultTestMethod.cs @@ -0,0 +1,22 @@ +/// +/// Copyright (c) 2015 Sensus Metering Systems +/// +using System; + +namespace TBF.BenchControl.GenericDevices +{ + public interface ISimultTestMethod : ITestMethod + { + /// + /// True = execute this test method (communication with the water meter, etc.) simultaneously + /// with the previous step or with purging + /// + bool SimultWithPrevious { get; } + + /// + /// True = execute this test method (communication with the water meter, etc.) simultaneously + /// with the next step or with emptying + /// + bool SimultWithNext { get; } + } +} diff --git a/TestBenchFramework/BenchControl/Sequences/MainSeq.cs b/TestBenchFramework/BenchControl/Sequences/MainSeq.cs index c531e7af9..a4ff2f060 100644 --- a/TestBenchFramework/BenchControl/Sequences/MainSeq.cs +++ b/TestBenchFramework/BenchControl/Sequences/MainSeq.cs @@ -5,6 +5,7 @@ using System; using System.Collections.Generic; using log4net; using TBF.UiBridge; +using TBF.BenchControl; using TBF.BenchControl.Operations; using TBF.BenchControl.GenericDevices; using TBF.Boxes; @@ -19,6 +20,39 @@ namespace TBF.BenchControl.Sequences public override string ToString() { return "Sequences.MainSeq"; } + + System.Windows.Forms.Form modelessDlg; + /// + delegate void iPerlCommFormDlgt(MainSeq myRef, Generic.IComponentCfg cfg, IList multiTestParams); + /// + void OpenIPerlCommForm(MainSeq myRef, Generic.IComponentCfg cfg, IList multiTestParams) + { + /// 1st argument + IList wMtrs = new List(); + foreach (var rr in sensPath.RegisterReaders) + { + if (rr is GenericDevices.IWaterMeter) wMtrs.Add(rr as GenericDevices.IWaterMeter); + } + + /// 2nd argument + TestMethods.iPerlCommunication.TestMethodCfg iPerlCfg = cfg as TestMethods.iPerlCommunication.TestMethodCfg; + + /// 3rd argument + IList iPerlCommParams = new List(); + foreach (var tp in multiTestParams) iPerlCommParams.Add(tp as TestMethods.iPerlCommunication.iPerlCommunicationParams); + + myRef.modelessDlg = new TestMethods.iPerlCommunication.iPerlCommunicationForm(wMtrs, iPerlCfg, iPerlCommParams); + myRef.modelessDlg.Show(); + } + + void CloseIPerlCommForm() + { + UiBridge.Bridge.OnCloseModelessForm(this, null); + modelessDlg = null; + } + + + /// Constructor public MainSeq() { @@ -39,6 +73,10 @@ namespace TBF.BenchControl.Sequences Selection selection; bool benchFilled = false; + int simultWithPurgingCount = 0; + Generic.IComponentCfg simultWithPurgingCfg; + IList simultWithPurgingParams; + StateMachine.LoadProcedure(true); // TODO: Implement as an operation so that the worker thread is not blocked Bridge.Bench2UI(ButtonsEtc.StopBtnEn); @@ -211,13 +249,85 @@ namespace TBF.BenchControl.Sequences fill_the_bench: - /// Purge - Begin - switch (Transition(purgeBegin, TransitionContext.PurgeBegin)) + /// + /// Analyze whether there are steps (e.g. iPerl communication) to be done simultaneously with purging + /// + simultWithPurgingCount = 0; + simultWithPurgingCfg = null; + simultWithPurgingParams = new List(); + foreach (var test in StateMachine.Tests) { - case Event.Error: goto error; - case Event.UiCmdStop: goto stop; + Generic.IComponent testMethodComp = TbfComponents.FindComponent(test.Method); + + ISimultTestMethod simultTest = testMethodComp as ISimultTestMethod; + if (simultTest == null) break; + + sensPath = StateMachine.GetMetersPath(test); + testMethodComp.Cfg.UpdateTestParams(test); + + if (!simultTest.SimultWithPrevious || + ((simultWithPurgingCount > 0) && (simultTest.Cfg != simultWithPurgingCfg))) + { + break; + } + + if (simultWithPurgingCount == 0) simultWithPurgingCfg = simultTest.Cfg; + + simultWithPurgingParams.Add(testMethodComp.Cfg.GetTestParams() as Generic.ITestParams); + + simultWithPurgingCount++; } + if (simultWithPurgingCount > 0) + { + /// Make sure the entry form is closed + if (UIFlowControl.Stop == WaitBeginFormClosed()) goto stop; + + OpenIPerlCommForm(this, simultWithPurgingCfg, 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 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(); + goto stop; + } + + completed = (modelessDlg is GenericDevices.IHasCompleted) + && (modelessDlg as GenericDevices.IHasCompleted).Completed; + } + while (!completed); + } + + assume_bench_filled: benchFilled = true; @@ -253,9 +363,11 @@ namespace TBF.BenchControl.Sequences if (selection == Selection.Cycle) { TimeEstimateTotal = 0; - foreach (var test in StateMachine.Tests) - { - TimeEstimateTotal += (test.Repeats * (test.TstTime + 10.0f)); + for (int i = simultWithPurgingCount; i < StateMachine.Tests.Count; i++) + { + Entities.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. @@ -271,18 +383,20 @@ namespace TBF.BenchControl.Sequences } TimeEstimateBeginRpts = 0; - foreach (var test in StateMachine.Tests) - { - /// Fetch the test paths and transitions - string errorMsg; - if (!StateMachine.GetPaths(test, out inPath, out benchPath, - out outPath, out sensPath, - out transitionBefore, out transitionAfter, - out errorMsg)) - { - UiBridge.Bridge.OnError(this, errorMsg); + for (int i = simultWithPurgingCount; i < StateMachine.Tests.Count; i++) + { + Entities.Test test = StateMachine.Tests[i]; + + /// Fetch the test paths and transitions + string errorMsg; + if (!StateMachine.GetPaths(test, out inPath, out benchPath, + out outPath, out sensPath, + out transitionBefore, out transitionAfter, + out errorMsg)) + { + UiBridge.Bridge.OnError(this, errorMsg); goto select_cycle_or_test; - } + } /// Update format for the water mass mass.Format = outPath.Balance.Format; @@ -290,20 +404,20 @@ namespace TBF.BenchControl.Sequences endMass.Format = outPath.Balance.Format; TimeEstimateOneTest = test.TstTime + 10.0f; - //-------------------------------------------------------------- + //-------------------------------------------------------------- ITestMethod testMethodSequence = TbfComponents.FindComponent(test.Method) as ITestMethod; if (testMethodSequence != null && testMethodSequence.CanTest(StateMachine.Procedure.MetersKind)) { StateMachine.LoadTestParams(test); - if (BenchInfo != null && sensPath.RegisterReaders != null) - { - foreach (var rr in sensPath.RegisterReaders) - if (rr is WaterMeters.iPerl.WaterMeter) - (rr as WaterMeters.iPerl.WaterMeter).BenchName = BenchInfo.TestBenchId; - } + if (BenchInfo != null && sensPath.RegisterReaders != null) + { + foreach (var rr in sensPath.RegisterReaders) + if (rr is WaterMeters.iPerl.WaterMeter) + (rr as WaterMeters.iPerl.WaterMeter).BenchName = BenchInfo.TestBenchId; + } - e = testMethodSequence.Execute(test); + e = testMethodSequence.Execute(test); if (e.Contains(Event.ConfigurationError)) goto select_cycle_or_test; if (e.Contains(Event.Error)) goto error; diff --git a/TestBenchFramework/BenchControl/StateMachine.cs b/TestBenchFramework/BenchControl/StateMachine.cs index 1816eecbb..11bc26b6e 100644 --- a/TestBenchFramework/BenchControl/StateMachine.cs +++ b/TestBenchFramework/BenchControl/StateMachine.cs @@ -416,7 +416,6 @@ namespace TBF.BenchControl pfeed = null; pben = null; pout = null; - pmtrs = null; transitionBefore = null; transitionAfter = null; @@ -435,22 +434,7 @@ namespace TBF.BenchControl if (test.OutputPath == path.Name) { pout = new OutputPath(path, components); break; } } - foreach (var path in metersPaths) - { - if (test.MetersPath == path.Name) { pmtrs = new MetersPath(path, components); break; } - } - if (pmtrs != null) - { - int count = Math.Min(Program.WMsCount, pmtrs.RegisterReaders.Length); - for (int i = 0; i < count; i++) - { - if ((pmtrs.RegisterReaders[i] != null) && - (pmtrs.RegisterReaders[i].Cfg.DebugLevel == Entities.DebugMode.DetectedOff)) - { - pmtrs.RegisterReaders[i] = null; - } - } - } + pmtrs = GetMetersPath(test); foreach (var tr in TransitionSequences) { @@ -480,6 +464,33 @@ namespace TBF.BenchControl return true; } + + /// + /// Updates paths based on the selected test + /// + public static MetersPath GetMetersPath(Entities.Test test) + { + MetersPath pmtrs = null; + foreach (var path in metersPaths) + { + if (test.MetersPath == path.Name) { pmtrs = new MetersPath(path, components); break; } + } + if (pmtrs != null) + { + int count = Math.Min(Program.WMsCount, pmtrs.RegisterReaders.Length); + for (int i = 0; i < count; i++) + { + if ((pmtrs.RegisterReaders[i] != null) && + (pmtrs.RegisterReaders[i].Cfg.DebugLevel == Entities.DebugMode.DetectedOff)) + { + pmtrs.RegisterReaders[i] = null; + } + } + } + return pmtrs; + } + + /// /// Stops the state machine (and the worker thread) /// diff --git a/TestBenchFramework/BenchControl/TestMethods/iPerlCommunication/TestMethod.cs b/TestBenchFramework/BenchControl/TestMethods/iPerlCommunication/TestMethod.cs index 653ff95d4..2267df844 100644 --- a/TestBenchFramework/BenchControl/TestMethods/iPerlCommunication/TestMethod.cs +++ b/TestBenchFramework/BenchControl/TestMethods/iPerlCommunication/TestMethod.cs @@ -10,7 +10,7 @@ using TBF.BenchControl; namespace TBF.BenchControl.TestMethods.iPerlCommunication { - public class TestMethod : ComponentBase, GenericDevices.ITestMethod, Generic.IDevice + public class TestMethod : ComponentBase, GenericDevices.ISimultTestMethod, Generic.IDevice { private static readonly ILog log = LogManager.GetLogger(typeof(TestMethod)); protected static readonly ILog rfidDataLogger = LogManager.GetLogger("RfidData"); @@ -19,6 +19,8 @@ namespace TBF.BenchControl.TestMethods.iPerlCommunication readonly TestMethodCfg testMethodCfg; + public bool SimultWithPrevious { get { return testMethodCfg.TestParams.SimultWithPrevious; } } + public bool SimultWithNext { get { return testMethodCfg.TestParams.SimultWithNext; } } public bool Evaluate { get { return false; } } public bool Publish { get { return false; } } public bool CanTest(Entities.MetersKind meters) { return meters == Entities.MetersKind.Single; } diff --git a/TestBenchFramework/BenchControl/TestMethods/iPerlCommunication/TestMethodCfg.cs b/TestBenchFramework/BenchControl/TestMethods/iPerlCommunication/TestMethodCfg.cs index 247d59205..d5dc4d927 100644 --- a/TestBenchFramework/BenchControl/TestMethods/iPerlCommunication/TestMethodCfg.cs +++ b/TestBenchFramework/BenchControl/TestMethods/iPerlCommunication/TestMethodCfg.cs @@ -1,6 +1,5 @@ /// /// Copyright (c) 2015 Sensus Metering Systems -/// Author: Milan Hanajík /// using System; using System.Collections.Generic; diff --git a/TestBenchFramework/BenchControl/TestMethods/iPerlCommunication/iPerlCommunicationForm.cs b/TestBenchFramework/BenchControl/TestMethods/iPerlCommunication/iPerlCommunicationForm.cs index cbab48d7a..43bcc37aa 100644 --- a/TestBenchFramework/BenchControl/TestMethods/iPerlCommunication/iPerlCommunicationForm.cs +++ b/TestBenchFramework/BenchControl/TestMethods/iPerlCommunication/iPerlCommunicationForm.cs @@ -1,6 +1,5 @@ /// /// Copyright (c) 2015 Sensus Metering Systems -/// Author: Milan Hanajík /// using System; using System.Collections.Generic; @@ -227,32 +226,34 @@ namespace TBF.BenchControl.TestMethods.iPerlCommunication readonly bool[] disabled; - Entities.TestResult tr; - int textBoxesCount; Label[] labels; TextBox[] messages; - static TestMethodCfg cfg; - static IList waterMeters; - - Modbus.QuidoRS.QuidoRS quido; + static IList waterMeters; + + Modbus.QuidoRS.QuidoRS quido; /// /// RFID multiplexer PCB / RFID serial port and worker thread related variables /// - static string activity; - static int currentGroup; /// form -> worker thread (0 = none) + static TestMethodCfg cfg; + static IList multiTestParams; + + + static int currentActivityStep; + static int currentGroup; /// form -> worker thread (0 = none) static int lastGroup; static int completedCommCount; /// Number of completed communication steps static IList workerThreads; static IList rfidPortNrs; - static IList stopWorkerThreads; /// form -> worker thread + static bool stopWorkerThreads; /// form -> worker thread - /// Parameterless constructor for 3 watermeters + + /// Parameterless constructor (without watermeters, threads) public iPerlCommunicationForm() { InitializeComponent(); @@ -286,16 +287,7 @@ namespace TBF.BenchControl.TestMethods.iPerlCommunication wmTextBox46, wmTextBox47, wmTextBox48, }; - currentGroup = 0; - lastGroup = 0; /// group numbers are >=1, lastGroup == 0 means no group - completedCommCount = 0; - - workerThreads = new List(); - rfidPortNrs = new List(); - stopWorkerThreads = new List(); - formCompleted = false; - tr = null; /// Find QuidoRS foreach (var comp in StateMachine.Components) @@ -328,63 +320,97 @@ namespace TBF.BenchControl.TestMethods.iPerlCommunication }; } + /// - /// Constructor + /// Constructor with a list of watermeters. + /// Creates a list of iPerl-s, re-shuffles UI conrols and allocates 'disabled' array. /// /// Number of text boxes for serial numbers - public iPerlCommunicationForm(TestMethodCfg cfg, IList waterMeters, string activity) + public iPerlCommunicationForm(IList waterMeters) : this() + { + this.WaterMetersCount = waterMeters.Count; + iPerlCommunicationForm.waterMeters = new List(); + /// + foreach (var wm in waterMeters) + { + WaterMeters.iPerl.WaterMeter iPerl = wm as WaterMeters.iPerl.WaterMeter; + iPerlCommunicationForm.waterMeters.Add(iPerl); + } + + ShuffleTextBoxes(this.WaterMetersCount, Program.LineSize); + + disabled = new bool[this.WaterMetersCount]; + + /// + /// Prepare worker threads, 'rfidPortNrs', 'lastGroup', etc.. + /// + workerThreads = new List(); + rfidPortNrs = new List(); + + currentActivityStep = 0; + currentGroup = 0; + lastGroup = 0; /// group numbers are >=1, lastGroup == 0 means no group + completedCommCount = 0; + stopWorkerThreads = false; + + foreach (var iPerl in iPerlCommunicationForm.waterMeters) + { + if (!rfidPortNrs.Contains(iPerl.MuxBoardNr)) + { + rfidPortNrs.Add(iPerl.MuxBoardNr); + + if (workerThreads.Count < NrThreads) + { + Thread thread = new Thread(iPerlCommunicationForm.Worker); + workerThreads.Add(thread); + } + } + if (iPerl.Group > lastGroup) lastGroup = iPerl.Group; + } + } + + + /// + /// Constructor for one iPerlCommunication 'test' + /// + /// Number of text boxes for serial numbers + public iPerlCommunicationForm(IList waterMeters, + TestMethodCfg cfg, iPerlCommunicationParams testParams) + : this(waterMeters) { iPerlCommunicationForm.cfg = cfg; - iPerlCommunicationForm.activity = activity; - this.WaterMetersCount = waterMeters.Count; - iPerlCommunicationForm.waterMeters = new List(); -#if DEFINE - foreach (var wm in waterMeters) - { - WaterMeters.iPerl.WaterMeter iPerlWM = wm as WaterMeters.iPerl.WaterMeter; - iPerlCommunicationForm.waterMeters.Add(iPerlWM); - if (iPerlWM.Group > lastGroup) lastGroup = iPerlWM.Group; - if (!rfidPortNrs.Contains(iPerlWM.RfidComPortNr)) - { - int threadId = workerThreads.Count; - Thread thread = new Thread(iPerlCommunicationForm.Worker); - workerThreads.Add(thread); - rfidPortNrs.Add(iPerlWM.RfidComPortNr); - stopWorkerThreads.Add(false); - thread.Start(new Boxes.IntBox(threadId)); - } - } -#else - foreach (var wm in waterMeters) - { - WaterMeters.iPerl.WaterMeter iPerlWM = wm as WaterMeters.iPerl.WaterMeter; - iPerlCommunicationForm.waterMeters.Add(iPerlWM); - if (!rfidPortNrs.Contains(iPerlWM.MuxBoardNr)) - { - rfidPortNrs.Add(iPerlWM.MuxBoardNr); + iPerlCommunicationForm.multiTestParams = new List(); + iPerlCommunicationForm.multiTestParams.Add(testParams); - int newThreadId = workerThreads.Count; - if (newThreadId < NrThreads) - { - Thread thread = new Thread(iPerlCommunicationForm.Worker); - workerThreads.Add(thread); - stopWorkerThreads.Add(false); - thread.Start(new Boxes.IntBox(newThreadId)); - } - } - if (iPerlWM.Group > lastGroup) lastGroup = iPerlWM.Group; - } -#endif - activityLabel.Text = activity; + activityLabel.Text = testParams.Activity; - ShuffleTextBoxes(this.WaterMetersCount, Program.LineSize); - - disabled = new bool[this.WaterMetersCount]; + /// Start worker threads + int wtId = 0; + foreach (var wt in workerThreads) wt.Start(new Boxes.IntBox(wtId++)); } + /// + /// Constructor for multiple iPerlCommunication 'tests' + /// + /// Number of text boxes for serial numbers + public iPerlCommunicationForm(IList waterMeters, TestMethodCfg cfg, + IList multiTestParams) + : this(waterMeters) + { + iPerlCommunicationForm.cfg = cfg; + iPerlCommunicationForm.multiTestParams = multiTestParams; + + if (multiTestParams.Count > 0) activityLabel.Text = multiTestParams[0].Activity; + + /// Start worker threads + int wtId = 0; + foreach (var wt in workerThreads) wt.Start(new Boxes.IntBox(wtId++)); + } + + /// /// Make sure the layout of labels/text boxes on the screen /// corresponds to the layout of watermeters of the test bench. @@ -422,6 +448,7 @@ namespace TBF.BenchControl.TestMethods.iPerlCommunication } } + private void iPerlCommunicationForm_Load(object sender, EventArgs e) { Localize(); @@ -457,6 +484,7 @@ namespace TBF.BenchControl.TestMethods.iPerlCommunication Top = (ls.iPerlCommunicationsFormTop != 0) ? ls.iPerlCommunicationsFormTop : 150; } + private void NormalClose() { CommCompletedHandler = null; @@ -471,35 +499,6 @@ namespace TBF.BenchControl.TestMethods.iPerlCommunication Close(); } - void OnAdjustmentInProgress(object sender, UiBridge.AdjustmentInProgressEventArgs args) - { - tr = args.TestResult; - Redraw(); - } - - void Redraw() - { - if (tr != null) - { - for (int i = 0; i < textBoxesCount; i++) - { - messages[i].Text = tr.Meters[i].VolumeErrorPct.ToString("F1"); - } - } - } - - private void WMErrorsForm_Paint(object sender, PaintEventArgs e) - { - //if (tr != null) - //{ - // System.Drawing.Graphics graphics = this.CreateGraphics(); - - // for (int i = 0; i < WaterMetersCount; i++) - // { - // PaintOne(graphics, rects[i], tr.Meters[i].VolumeErrorPct, tr.ErrLimLo, tr.ErrLimHi); - // } - //} - } #region Forced close handling @@ -517,6 +516,8 @@ namespace TBF.BenchControl.TestMethods.iPerlCommunication CommCompletedHandler = null; AllCompletedHandler = null; + stopWorkerThreads = true; + DialogResult = DialogResult.Cancel; Close(); } @@ -532,62 +533,83 @@ namespace TBF.BenchControl.TestMethods.iPerlCommunication { int threadId = (threadData as Boxes.IntBox).Val; - if (threadId == 0) - { - rfidDataLogger.InfoFormat(""); /// Makes the log more readable when there is a lot of data - rfidDataLogger.WarnFormat("Activity = {0}", activity); - rfidDataLogger.InfoFormat(""); /// Makes the log more readable when there is a lot of data - } + int activityStep = 0; /// activity step > 0 in case multiTestParams are used - for (int group = 1; group <= lastGroup; group++) - { - while (currentGroup != group && !stopWorkerThreads[threadId]) Thread.Sleep(50); + foreach (var testParams in multiTestParams) + { + string activity = testParams.Activity; /// Current activity - if (stopWorkerThreads[threadId]) break; - for (int rfidPortIx = threadId; rfidPortIx < threadId + 4; rfidPortIx += NrThreads) - { - int rfidPortNr = rfidPortNrs[rfidPortIx]; - int wmNr = 0; - bool wmFound = false; - foreach (var wm in waterMeters) - { - if ((wm.MuxBoardNr == rfidPortNr) && (wm.Group == group)) - { - wmFound = true; + if (threadId == 0) + { + rfidDataLogger.InfoFormat(""); /// Makes the log more readable when there is a lot of data + rfidDataLogger.WarnFormat("Activity = {0}", activity); + rfidDataLogger.InfoFormat(""); /// Makes the log more readable when there is a lot of data + } - CommErr error; - string resultStr = string.Empty; + for (int group = 1; group <= lastGroup; group++) + { + /// Synchronize with QuidoRS and other threads + while (((currentGroup != group) || (activityStep != currentActivityStep)) && !stopWorkerThreads) + { + Thread.Sleep(50); + } - if (activity.ToLower().Contains(ReadConfigurationStr.ToLower())) error = ReadConfiguration(wm, ref resultStr); - else if (activity.ToLower().Contains(SetTestModeStr.ToLower())) error = SetTestMode(wm, ref resultStr); - else if (activity.ToLower().Equals(SetActiveModeStr.ToLower())) error = SetActiveMode(wm, ref resultStr); - else if (activity.ToLower().Equals(ReadCalibrationStr.ToLower())) error = ReadCalibration(wm, ref resultStr); - else if (activity.ToLower().Contains(WriteCalibrationFactorStr.ToLower())) error = WriteCalibrationFactor(wm, ref resultStr); - else if (activity.ToLower().Equals(ResetQ2CorrectionStr.ToLower())) error = ResetQ2Correction(wm, ref resultStr); - else if (activity.ToLower().Equals(WriteQ2CorrectionStr.ToLower())) error = WriteQ2Correction(wm, ref resultStr); - else - { - error = CommErr.None; - resultStr = "Invalid activity"; - } + if (stopWorkerThreads) break; - if (error == CommErr.None) OnCommCompleted(null, new CommCompletedEventArgs(threadId, wmNr, resultStr)); - else if (wm.Disabled || error == CommErr.Disabled) OnCommCompleted(null, new CommCompletedEventArgs(threadId, wmNr, "Watermeter is disabled")); - else - { - OnCommCompleted(null, new CommCompletedEventArgs(threadId, wmNr, string.Format("{0} failed ({1}) !!!", activity, error))); - rfidDataLogger.ErrorFormat("Group={0}, Board={1}, {2} failed ({3}) !!!", currentGroup, wm.MuxBoardNr, activity, error); - wm.Disabled = true; - } - break; - } - wmNr++; - } + for (int rfidPortIx = threadId; rfidPortIx < threadId + 4; rfidPortIx += NrThreads) + { + int rfidPortNr = rfidPortNrs[rfidPortIx]; + int wmNr = 0; + bool wmFound = false; - if (!wmFound) OnCommCompleted(null, new CommCompletedEventArgs(threadId, -1, string.Empty)); /// Send negative wmNr - } - } + foreach (var wm in waterMeters) + { + if ((wm.MuxBoardNr == rfidPortNr) && (wm.Group == group)) + { + wmFound = true; + + CommErr error; + string resultStr = string.Empty; + + if (activity.ToLower().Contains(ReadConfigurationStr.ToLower())) error = ReadConfiguration(wm, ref resultStr); + else if (activity.ToLower().Contains(SetTestModeStr.ToLower())) error = SetTestMode(wm, ref resultStr); + else if (activity.ToLower().Equals(SetActiveModeStr.ToLower())) error = SetActiveMode(wm, ref resultStr); + else if (activity.ToLower().Equals(ReadCalibrationStr.ToLower())) error = ReadCalibration(wm, ref resultStr); + else if (activity.ToLower().Contains(WriteCalibrationFactorStr.ToLower())) error = WriteCalibrationFactor(wm, ref resultStr); + else if (activity.ToLower().Equals(ResetQ2CorrectionStr.ToLower())) error = ResetQ2Correction(wm, ref resultStr); + else if (activity.ToLower().Equals(WriteQ2CorrectionStr.ToLower())) error = WriteQ2Correction(wm, ref resultStr); + else + { + error = CommErr.None; + resultStr = "Invalid activity"; + } + + if (error == CommErr.None) OnCommCompleted(null, new CommCompletedEventArgs(threadId, wmNr, resultStr)); + else if (wm.Disabled || error == CommErr.Disabled) OnCommCompleted(null, new CommCompletedEventArgs(threadId, wmNr, "Watermeter is disabled")); + else + { + OnCommCompleted(null, new CommCompletedEventArgs(threadId, wmNr, string.Format("{0} failed ({1}) !!!", activity, error))); + rfidDataLogger.ErrorFormat("Group={0}, Board={1}, {2} failed ({3}) !!!", currentGroup, wm.MuxBoardNr, activity, error); + wm.Disabled = true; + } + break; + } + wmNr++; + } + + if (!wmFound) OnCommCompleted(null, new CommCompletedEventArgs(threadId, -1, string.Empty)); /// Send negative wmNr + + if (stopWorkerThreads) break; + } + + if (stopWorkerThreads) break; + } /// for (int group + + activityStep++; + + if (stopWorkerThreads) break; + } } @@ -603,7 +625,7 @@ namespace TBF.BenchControl.TestMethods.iPerlCommunication /// The activity is "Read configuration" (this enables the watermeter, resets error flag) /// or "Read configuration if enabled" (this keeps th error flag). /// - if (!activity.ToLower().Contains(" if enabled")) + if (!multiTestParams[currentActivityStep].Activity.ToLower().Contains(" if enabled")) { wm.Disabled = false; } @@ -648,9 +670,9 @@ namespace TBF.BenchControl.TestMethods.iPerlCommunication Byte testModeConfig = 0xA0; /// Default value /// - if (activity.Length > SetTestModeStr.Length) + if (multiTestParams[currentActivityStep].Activity.Length > SetTestModeStr.Length) { - string testModeConfigStr = activity.Substring(SetTestModeStr.Length + 1); + string testModeConfigStr = multiTestParams[currentActivityStep].Activity.Substring(SetTestModeStr.Length + 1); UInt16 byteVal; if (UInt16.TryParse(testModeConfigStr, NumberStyles.HexNumber, CultureInfo.CurrentCulture, out byteVal) && byteVal <= 255) { @@ -834,9 +856,9 @@ namespace TBF.BenchControl.TestMethods.iPerlCommunication UInt16 newCalibFactor = 3000; /// Default value /// - if (activity.Length > WriteCalibrationFactorStr.Length) + if (multiTestParams[currentActivityStep].Activity.Length > WriteCalibrationFactorStr.Length) { - string calibFactrorStr = activity.Substring(WriteCalibrationFactorStr.Length + 1); + string calibFactrorStr = multiTestParams[currentActivityStep].Activity.Substring(WriteCalibrationFactorStr.Length + 1); UInt16 val; if (UInt16.TryParse(calibFactrorStr, out val) && val > 0) { @@ -1012,14 +1034,25 @@ namespace TBF.BenchControl.TestMethods.iPerlCommunication if (currentGroup < lastGroup) { /// Go to the next step / next group - if (quido != null) + currentGroup++; + if (quido != null) { - quido.SetOutputs((ushort)(16 - currentGroup - 1)); + quido.SetOutputs((ushort)(16 - currentGroup)); Thread.Sleep(100); } - currentGroup++; } - else + else if (currentActivityStep + 1 < multiTestParams.Count) + { + currentActivityStep++; + activityLabel.Text = multiTestParams[currentActivityStep].Activity; + currentGroup = 1; + if (quido != null) + { + quido.SetOutputs((ushort)(16 - currentGroup)); + Thread.Sleep(100); + } + } + else { /// Wait until all threads are finished workerThreads[data.ThreadId].Join(2000); diff --git a/TestBenchFramework/BenchControl/TestMethods/iPerlCommunication/iPerlCommunicationForm.designer.cs b/TestBenchFramework/BenchControl/TestMethods/iPerlCommunication/iPerlCommunicationForm.designer.cs index 4a79332a0..6012874ec 100644 --- a/TestBenchFramework/BenchControl/TestMethods/iPerlCommunication/iPerlCommunicationForm.designer.cs +++ b/TestBenchFramework/BenchControl/TestMethods/iPerlCommunication/iPerlCommunicationForm.designer.cs @@ -1210,7 +1210,6 @@ namespace TBF.BenchControl.TestMethods.iPerlCommunication this.Text = "Water Meter States"; this.TopMost = true; this.Load += new System.EventHandler(this.iPerlCommunicationForm_Load); - this.Paint += new System.Windows.Forms.PaintEventHandler(this.WMErrorsForm_Paint); this.ResumeLayout(false); this.PerformLayout(); diff --git a/TestBenchFramework/BenchControl/TestMethods/iPerlCommunication/iPerlCommunicationParams.cs b/TestBenchFramework/BenchControl/TestMethods/iPerlCommunication/iPerlCommunicationParams.cs index 9354f0b14..c7174e2ff 100644 --- a/TestBenchFramework/BenchControl/TestMethods/iPerlCommunication/iPerlCommunicationParams.cs +++ b/TestBenchFramework/BenchControl/TestMethods/iPerlCommunication/iPerlCommunicationParams.cs @@ -1,6 +1,5 @@ /// /// Copyright (c) 2015 Sensus Metering Systems -/// Author: Milan Hanajík /// using System; using System.IO; @@ -14,16 +13,22 @@ namespace TBF.BenchControl.TestMethods.iPerlCommunication public class iPerlCommunicationParams : TestParamsBase, IParamsProvider, ITestParams { public string Activity; /// Communication activity + public bool SimultWithPrevious; + public bool SimultWithNext; public override void InitializeAll() { Activity = "Read Configuration"; + SimultWithPrevious = false; + SimultWithNext = false; } string[] paramNames = new string[] { Strings.Activity, + Strings.Simultaneous_with_previous_step, + Strings.Simultaneous_with_next_step, }; public override string ParamName(int i) { return paramNames[i]; } public override int ParamsCount() { return paramNames.Length; } @@ -33,6 +38,8 @@ namespace TBF.BenchControl.TestMethods.iPerlCommunication switch (i) { case 0: return Activity; + case 1: return (SimultWithPrevious ? Strings.yes : Strings.no); + case 2: return (SimultWithNext ? Strings.yes : Strings.no); default: return string.Empty; } } @@ -42,6 +49,8 @@ namespace TBF.BenchControl.TestMethods.iPerlCommunication switch (i) { case 0: Activity = strValue; return; + case 1: SimultWithPrevious = strValue.Equals(Strings.yes); return; + case 2: SimultWithNext = strValue.Equals(Strings.yes); return; default: return; } } @@ -54,10 +63,17 @@ namespace TBF.BenchControl.TestMethods.iPerlCommunication { case 0: return true; + case 1: + case 2: + if (strValue.Equals(Strings.yes) || strValue.Equals(Strings.no)) return true; + break; default: message = "Invalid index"; return false; } + + message = ParamName(i) + " is invalid"; + return false; } public override void UpdateTestParams(Entities.ComponentTest dbEntity) @@ -73,6 +89,8 @@ namespace TBF.BenchControl.TestMethods.iPerlCommunication test = dbEntity.Test; Activity = tmp.Activity; + SimultWithPrevious = tmp.SimultWithPrevious; + SimultWithNext = tmp.SimultWithNext; } catch { diff --git a/TestBenchFramework/BenchControl/TestMethods/iPerlCommunication/iPerlCommunicationSeq.cs b/TestBenchFramework/BenchControl/TestMethods/iPerlCommunication/iPerlCommunicationSeq.cs index 5512b9542..9b3456967 100644 --- a/TestBenchFramework/BenchControl/TestMethods/iPerlCommunication/iPerlCommunicationSeq.cs +++ b/TestBenchFramework/BenchControl/TestMethods/iPerlCommunication/iPerlCommunicationSeq.cs @@ -16,21 +16,30 @@ namespace TBF.BenchControl.TestMethods.iPerlCommunication { private static readonly ILog log = LogManager.GetLogger(typeof(iPerlCommunicationSeq)); + System.Windows.Forms.Form modelessDlg; /// - delegate void iPerlCommFormDlgt(iPerlCommunicationSeq myRef, TestMethodCfg cfg, string activity); + delegate void iPerlCommFormDlgt(iPerlCommunicationSeq myRef, TestMethodCfg cfg, iPerlCommunicationParams testParams); /// - void OpenIPerlCommForm(iPerlCommunicationSeq myRef, TestMethodCfg cfg, string activity) + void OpenIPerlCommForm(iPerlCommunicationSeq myRef, TestMethodCfg cfg, iPerlCommunicationParams testParams) { IList wMtrs = new List(); foreach (var rr in sensPath.RegisterReaders) { if (rr is GenericDevices.IWaterMeter) wMtrs.Add(rr as GenericDevices.IWaterMeter); } - myRef.modelessDlg = new iPerlCommunicationForm(cfg, wMtrs, activity); - modelessDlg.Show(); + myRef.modelessDlg = new iPerlCommunicationForm(wMtrs, cfg, testParams); + myRef.modelessDlg.Show(); } + + void CloseIPerlCommForm() + { + UiBridge.Bridge.OnCloseModelessForm(this, null); + modelessDlg = null; + } + + /// /// Flying start mass collection method sequence /// @@ -46,18 +55,10 @@ namespace TBF.BenchControl.TestMethods.iPerlCommunication IList e = new List(); /// Events from currently running operations Event retVal = Event.Done; checkUiOp = new Operations.CheckUIOp(true); /// Runs in more then one state + modelessDlg = null; processDataLoggingOp = new TBF.BenchControl.Operations.ProcessDataLoggingOp(processDataLogger, this); - //==================================== - // Transition or SetRoute - Start - //==================================== - switch (Transition(transitionBefore, TransitionContext.BeforeTest)) - { - case Event.Error: { retVal = Event.Error; goto stopTest; } - case Event.UiCmdStop: { retVal = Event.UiCmdStop; goto stopTest; } - } - const string Q2correctedFromCmd = "Q2 corrected from "; if (testParams.Activity.Contains(Q2correctedFromCmd)) @@ -103,42 +104,41 @@ namespace TBF.BenchControl.TestMethods.iPerlCommunication iPerl.NominalTestFlow = 500.0 * (double)(test.Qfrom + test.Qto); /// Ave. + convert to liter/hour } } - - IList rList = new List(1); - rList.Add(Event.Done); - return rList; } else { /// /// Show the modeless dialog with error indication /// - Program.MainWnd.Invoke(new iPerlCommFormDlgt(OpenIPerlCommForm), new object[] { this, cfg, testParams.Activity }); - } + Program.MainWnd.Invoke(new iPerlCommFormDlgt(OpenIPerlCommForm), new object[] { this, cfg, testParams }); - loop: - //------------------------------------------------ - Bridge.OnActivity(this, Strings.Test_in_progress); - //------------------------------------------------ + //------------------------------------------------ + Bridge.OnActivity(this, Strings.iPerl_Communication_in_progress); + //------------------------------------------------ - /// Make sure the CycleBeginForm is closed so that water meter data (s/n) can be copied into results - if (UIFlowControl.Stop == WaitBeginFormClosed()) goto stopTest; + bool stopPressed = false; /// true when STOP button pressed + bool completed = false; - /// Test 'Quit' - if ((modelessDlg is GenericDevices.IHasCompleted) && !(modelessDlg as GenericDevices.IHasCompleted).Completed) - { - goto loop; /// Modeless dilaog not closed, keep looping - } - modelessDlg = null; /// Modeless dialog is closed now + State.Create("iPerlCommunicationSeq : Wait until the entry form is closed") + .AddOperation(checkUiOp) + .EnterState(); + do + { + e = StateMachine.WaitRunDevsRunOps(); + stopPressed = e.Contains(Event.UiCmdStop); + completed = (modelessDlg is GenericDevices.IHasCompleted) + && (modelessDlg as GenericDevices.IHasCompleted).Completed; + } + while (!stopPressed && !completed); - stopTest: + if (stopPressed) + { + CloseIPerlCommForm(); + retVal = Event.UiCmdStop; + } - /// Transition sequence at the end of test - /// Prevent overwriting 'retVal' in case it was set to non-default value earlier - switch (Transition(transitionAfter, TransitionContext.AfterTest)) - { - case Event.Error: { if (retVal == Event.Done) retVal = Event.Error; break; } - case Event.UiCmdStop: { if (retVal == Event.Done) retVal = Event.UiCmdStop; break; } + /// Test 'Quit' + modelessDlg = null; /// Modeless dialog is closed now } /// Create a list with one item 'retVal' (default is Event.Done) and return it diff --git a/TestBenchFramework/Properties/AssemblyInfo.cs b/TestBenchFramework/Properties/AssemblyInfo.cs index ecc69c56a..e4db76628 100644 --- a/TestBenchFramework/Properties/AssemblyInfo.cs +++ b/TestBenchFramework/Properties/AssemblyInfo.cs @@ -29,5 +29,5 @@ using System.Runtime.InteropServices; // Build Number // Revision // -[assembly: AssemblyVersion("1.5.105.1")] -[assembly: AssemblyFileVersion("1.5.105.1")] +[assembly: AssemblyVersion("1.5.106.1")] +[assembly: AssemblyFileVersion("1.5.106.1")] diff --git a/TestBenchFramework/Resources/Strings.Designer.cs b/TestBenchFramework/Resources/Strings.Designer.cs index 6e128a6e4..c3783e531 100644 --- a/TestBenchFramework/Resources/Strings.Designer.cs +++ b/TestBenchFramework/Resources/Strings.Designer.cs @@ -1077,6 +1077,15 @@ namespace TBF.Resources { } } + /// + /// Looks up a localized string similar to iPerl Communication in progress. + /// + internal static string iPerl_Communication_in_progress { + get { + return ResourceManager.GetString("iPerl_Communication_in_progress", resourceCulture); + } + } + /// /// Looks up a localized string similar to Less. /// @@ -2256,6 +2265,24 @@ namespace TBF.Resources { } } + /// + /// Looks up a localized string similar to Simultaneous with next step. + /// + internal static string Simultaneous_with_next_step { + get { + return ResourceManager.GetString("Simultaneous_with_next_step", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Simultaneous with previous step. + /// + internal static string Simultaneous_with_previous_step { + get { + return ResourceManager.GetString("Simultaneous_with_previous_step", resourceCulture); + } + } + /// /// Looks up a localized string similar to Single. /// diff --git a/TestBenchFramework/Resources/Strings.resx b/TestBenchFramework/Resources/Strings.resx index 6cdfbe61d..09aeca53a 100644 --- a/TestBenchFramework/Resources/Strings.resx +++ b/TestBenchFramework/Resources/Strings.resx @@ -1096,4 +1096,13 @@ Publish + + Simultaneous with next step + + + Simultaneous with previous step + + + iPerl Communication in progress + \ No newline at end of file diff --git a/TestBenchFramework/TBF.csproj b/TestBenchFramework/TBF.csproj index 89e84ca98..0a8145569 100644 --- a/TestBenchFramework/TBF.csproj +++ b/TestBenchFramework/TBF.csproj @@ -277,6 +277,7 @@ +