From 1c6f9af2bb6c7dd588e6f0dab0a2836e409c1f93 Mon Sep 17 00:00:00 2001 From: Marek Frniak Date: Thu, 10 Sep 2026 14:08:00 +0200 Subject: [PATCH] : Add standalone Genesis preadjustment activities, fix configuration control and increase revision to 3.9.3146.101 Cause: - GenesisCommunication did not expose GCI preadjustment phases as selectable test activities. - Meter size and temperature inputs required by preadjustment could not be configured. - The configuration control incorrectly expected the iPerlCommunication configuration type. - Preadjustment results were not propagated to TBF test and meter results. Solution: 1. Added standalone preadjustment activities - Added Initialization, Detect, Preparation, Amplitude Test, Temperature Calibration, Push Temperature, Offset Test and Completion. - Each phase can be selected and executed independently. 2. Added preadjustment parameters - Added configurable meter size and temperature. - Added validation and supported meter-size selection. 3. Added batch preadjustment execution - Resolves enabled Genesis register readers and their slots. - Verifies that all readers use the same GCI Bridge instance. - Dispatches the selected activity through the corresponding GCI Bridge API. 4. Added result processing - Stores execution time and completion status. - Updates test and meter results according to the GCI response. 5. Fixed the configuration control - Corrected TestMethodCfgCtrl to accept the GenesisCommunication TestMethodCfg type. 6. Increased revision - Updated revision to 3.9.3146.101. --- TBF/Properties/AssemblyInfo.cs | 4 +- .../GenesisCommunicationSeq.cs | 218 ++++++++++++++++++ .../GenesisCommunication/TestMethodCfgCtrl.cs | 8 +- .../iPerlCommunicationParams.cs | 36 ++- 4 files changed, 259 insertions(+), 7 deletions(-) diff --git a/TBF/Properties/AssemblyInfo.cs b/TBF/Properties/AssemblyInfo.cs index f609c7113..b8a3f75e1 100644 --- a/TBF/Properties/AssemblyInfo.cs +++ b/TBF/Properties/AssemblyInfo.cs @@ -32,5 +32,5 @@ using System.Runtime.InteropServices; // Build Number // Revision // -[assembly: AssemblyVersion("3.9.3146.0")] -[assembly: AssemblyFileVersion("3.9.3146.0")] +[assembly: AssemblyVersion("3.9.3146.101")] +[assembly: AssemblyFileVersion("3.9.3146.101")] diff --git a/TBF/Rig/TestMethods/GenesisCommunication/GenesisCommunicationSeq.cs b/TBF/Rig/TestMethods/GenesisCommunication/GenesisCommunicationSeq.cs index 7c23bee5e..100b8ddf3 100644 --- a/TBF/Rig/TestMethods/GenesisCommunication/GenesisCommunicationSeq.cs +++ b/TBF/Rig/TestMethods/GenesisCommunication/GenesisCommunicationSeq.cs @@ -5,16 +5,27 @@ using System; using System.Collections.Generic; using System.Drawing; +using System.Globalization; +using System.Linq; +using System.Threading; using Common; +using CordonelPreadjustmentUi; +using CordonelPreadjustmentUi.Processes.Itinerary; using Config.Entities; +using GenesisCordonelInterface.API; using log4net; using RestClient; using Results.Entities; using TBF.Resources; using TBF.Rig.Generic; using TBF.Rig.Sequences; +using TBF.Rig.RegisterReaders.GenesisRegReader.implementations; using TBF.Rig.TestMethods.iPerlCommunication; using TBF.UiBridge; +using Xylem.Common.Logic.ProductionOrderCore.OrderData; +using Xylem.Common.Ui.CordonelPreadjustmentUi; +using GciBridgeType = TBF.Rig.BridgeComponents.GciBridge.GciBridge; +using GciPublicModels = GenesisCordonelInterface.API.PublicModels; /// Point definition namespace TBF.Rig.TestMethods.GenesisCommunication @@ -28,6 +39,14 @@ namespace TBF.Rig.TestMethods.GenesisCommunication public const string Q2correctionCheckCmd = "Q2 correction check "; public const string IperlCheckCmd = "iPERL_check "; public const string SimulateCmd = "simulate "; + public const string PreadjustmentInitializationStr = "Preadjustment Initialization"; + public const string PreadjustmentDetectStr = "Preadjustment Detect"; + public const string PreadjustmentPreparationStr = "Preadjustment Preparation"; + public const string PreadjustmentAmplitudeTestStr = "Preadjustment Amplitude Test"; + public const string PreadjustmentTemperatureCalibrationStr = "Preadjustment Temperature Calibration"; + public const string PreadjustmentPushTemperatureStr = "Preadjustment Push Temperature"; + public const string PreadjustmentOffsetTestStr = "Preadjustment Offset Test"; + public const string PreadjustmentCompletionStr = "Preadjustment Completion"; System.Windows.Forms.Form modelessDlg; @@ -71,6 +90,12 @@ namespace TBF.Rig.TestMethods.GenesisCommunication processDataLoggingOp = new TBF.Rig.Operations.ProcessDataLoggingOp(processDataLogger, this, false); + iPerlCommunicationParams genesisTestParams = testParams as iPerlCommunicationParams; + if (genesisTestParams != null && IsPreadjustmentActivity(genesisTestParams.Activity)) + { + return ExecutePreadjustment(test, method, genesisTestParams); + } + string cmd; if (testParams.Activity.ToLower().Equals(cmd = GenesisCommunicationForm.GetDefaultQ2CorrectionsStr.ToLower())) { @@ -410,6 +435,199 @@ namespace TBF.Rig.TestMethods.GenesisCommunication return new List { Event.Done }; } + private static bool IsPreadjustmentActivity(string activity) + { + return string.Equals(activity, PreadjustmentInitializationStr, StringComparison.OrdinalIgnoreCase) || + string.Equals(activity, PreadjustmentDetectStr, StringComparison.OrdinalIgnoreCase) || + string.Equals(activity, PreadjustmentPreparationStr, StringComparison.OrdinalIgnoreCase) || + string.Equals(activity, PreadjustmentAmplitudeTestStr, StringComparison.OrdinalIgnoreCase) || + string.Equals(activity, PreadjustmentTemperatureCalibrationStr, StringComparison.OrdinalIgnoreCase) || + string.Equals(activity, PreadjustmentPushTemperatureStr, StringComparison.OrdinalIgnoreCase) || + string.Equals(activity, PreadjustmentOffsetTestStr, StringComparison.OrdinalIgnoreCase) || + string.Equals(activity, PreadjustmentCompletionStr, StringComparison.OrdinalIgnoreCase); + } + + private IList ExecutePreadjustment(Test test, TestMethod method, iPerlCommunicationParams testParams) + { + DateTime startTime = DateTime.Now; + bool success = false; + string response = string.Empty; + List> readers = new List>(); + + TestProgressEventArgs.SetEstimatedTimes(new int[] { 0, 0, 0, 30, 0, 30, 0, 0 }); + Bridge.OnTestProgress(this, new TestProgressEventArgs(test, Progress.JustStarted)); + Bridge.OnActivity(this, testParams.Activity); + + try + { + readers = GetPreadjustmentReaders(test); + GciBridgeType bridge = GetCommonGciBridge(readers); + success = ExecutePreadjustmentActivity(bridge, readers, testParams, out response); + } + catch (Exception ex) + { + response = ex.Message; + log.Error(string.Format("{0} failed.", testParams.Activity), ex); + } + + UpdatePreadjustmentResult(test, method, readers, success, startTime); + + if (success) + log.InfoFormat("{0} finished successfully. {1}", testParams.Activity, response); + else + log.ErrorFormat("{0} failed. {1}", testParams.Activity, response); + + Bridge.OnActivity(this, string.Format("{0}: {1}", testParams.Activity, response)); + Bridge.OnTestProgress(this, new TestProgressEventArgs(test, Progress.Completed)); + Bridge.OnTestCompleted(this, new TestCompletedEventArgs(test.Name, ProcessData.BatchRslts.GetTestRslt(test.Name, test.Part))); + allResults.Info(TestResult2CsvLine(test.Name, test.Part)); + + return new List { Event.Done }; + } + + private static List> GetPreadjustmentReaders(Test test) + { + var metersPath = StateMachine.GetMetersPath(test); + if (metersPath == null || metersPath.RegisterReaders == null) + throw new InvalidOperationException("No register readers are configured for the test."); + + var readers = new List>(); + for (int meterPosition = 0; meterPosition < metersPath.RegisterReaders.Length; meterPosition++) + { + GenesisSmartReader reader = metersPath.RegisterReaders[meterPosition] as GenesisSmartReader; + if (reader == null) + continue; + + if (meterPosition < ProcessData.BatchRslts.Batch.WaterMeters.Count && ProcessData.BatchRslts.Batch.WaterMeters[meterPosition] != null && ProcessData.BatchRslts.Batch.WaterMeters[meterPosition].Disabled) + continue; + + if (reader.GetSlotNr <= 0) + throw new InvalidOperationException(string.Format("Genesis reader '{0}' has invalid slot number {1}.", reader.Name, reader.GetSlotNr)); + + readers.Add(new KeyValuePair(meterPosition, reader)); + } + + if (readers.Count == 0) + throw new InvalidOperationException("No enabled Genesis register reader with a valid slot was found."); + + if (readers.Select(item => item.Value.GetSlotNr).Distinct().Count() != readers.Count) + throw new InvalidOperationException("More than one Genesis register reader uses the same GCI slot."); + + return readers; + } + + private static GciBridgeType GetCommonGciBridge(IEnumerable> readers) + { + GciBridgeType commonBridge = null; + + foreach (KeyValuePair item in readers) + { + GciBridgeType bridge = item.Value.CommInterfaceBridge; + if (bridge == null) + throw new InvalidOperationException(string.Format("Genesis reader '{0}' has no valid GCI Bridge configured.", item.Value.Name)); + + if (commonBridge != null && !ReferenceEquals(commonBridge, bridge)) + throw new InvalidOperationException("Enabled Genesis readers do not use the same GCI Bridge instance."); + + commonBridge = bridge; + } + + return commonBridge; + } + + private static bool ExecutePreadjustmentActivity(GciBridgeType bridge, IList> readers, iPerlCommunicationParams testParams, out string response) + { + if (string.Equals(testParams.Activity, PreadjustmentInitializationStr, StringComparison.OrdinalIgnoreCase)) + { + MeterSize meterSize; + if (!Enum.TryParse(testParams.MeterSize, true, out meterSize) || meterSize == MeterSize.NA) + throw new InvalidOperationException(string.Format("Meter size '{0}' is not valid.", testParams.MeterSize)); + + var progress = new ProcessProgress + { + Setting = new PreAdjustmentSettingsContainer + { + TempOnly = false, + Culture = new CultureInfo("en-US"), + MeterSize = meterSize, + NumberOfPaths = 3, + OffsetTestSettlingTime = 0 + }, + IsAutomaticMode = true + }; + + var meterControls = new List(); + foreach (KeyValuePair item in readers) + { + var meterControl = new MeterStateControl(item.Value.GetSlotNr); + meterControl.SetChecked(true); + meterControl.IsEnabled = true; + meterControls.Add(meterControl); + } + + PublicModels.PreAdjustmentInitializationResult result = bridge.Preadjustment_Initialization(progress, meterControls); + response = result.ToString(); + return result.Success; + } + + if (string.Equals(testParams.Activity, PreadjustmentDetectStr, StringComparison.OrdinalIgnoreCase)) + { + var selectedSlots = readers.Select(item => new GciPublicModels.MeterBatchDebugStatus { Slot = item.Value.GetSlotNr, Selected = true }).ToList(); + PublicModels.PreadjustmentDetectResult result = bridge.PreAdjustment_DetectDirect(selectedSlots, CancellationToken.None); + response = result.ToString(); + return result.Success; + } + + if (string.Equals(testParams.Activity, PreadjustmentPushTemperatureStr, StringComparison.OrdinalIgnoreCase)) + { + // Keep temperature delivery as an explicit sibling GCI API activity. A procedure can run it simultaneously with temperature calibration. + bool pushed = bridge.PreAdjustment_PushTemperature(testParams.Temperature); + response = pushed ? string.Format("Temperature {0} °C was accepted.", testParams.Temperature) : "GCI preadjustment was not initialized; temperature was not accepted."; + return pushed; + } + + PublicModels.PreAdjustmentProcessResult processResult; + if (string.Equals(testParams.Activity, PreadjustmentPreparationStr, StringComparison.OrdinalIgnoreCase)) + processResult = bridge.PreAdjustment_PreparationDirect(); + else if (string.Equals(testParams.Activity, PreadjustmentAmplitudeTestStr, StringComparison.OrdinalIgnoreCase)) + processResult = bridge.PreAdjustment_AmplitudeTestDirect(); + else if (string.Equals(testParams.Activity, PreadjustmentTemperatureCalibrationStr, StringComparison.OrdinalIgnoreCase)) + processResult = bridge.PreAdjustment_TemperatureCalibrationDirect(); + else if (string.Equals(testParams.Activity, PreadjustmentOffsetTestStr, StringComparison.OrdinalIgnoreCase)) + processResult = bridge.PreAdjustment_OffsetTestDirect(); + else if (string.Equals(testParams.Activity, PreadjustmentCompletionStr, StringComparison.OrdinalIgnoreCase)) + processResult = bridge.PreAdjustment_CompletionDirect(); + else + throw new InvalidOperationException(string.Format("Unsupported preadjustment activity '{0}'.", testParams.Activity)); + + response = processResult.ToString(); + return processResult.Success; + } + + private static void UpdatePreadjustmentResult(Test test, TestMethod method, IEnumerable> readers, bool success, DateTime startTime) + { + TestRslt testResult = ProcessData.BatchRslts.GetTestRslt(test.Name, test.Part); + if (testResult == null) + return; + + testResult.MethodClass = method.ClassName; + testResult.StartTime = startTime; + testResult.EndTime = DateTime.Now; + testResult.TestTime = Math.Max(0, (int)(testResult.EndTime - startTime).TotalSeconds); + testResult.TestDone = true; + + foreach (KeyValuePair item in readers) + { + MeterTestRslt meterResult = ProcessData.BatchRslts.GetMeterTestRslt(test.Name, item.Key, CompoundMeterId.Single); + if (meterResult == null) + continue; + + meterResult.WaterMeter.SerialNr = item.Value.SerialNr; + meterResult.Passed = success; + meterResult.TestDone = true; + } + } + /// /// Read default Q2 correction factors from a REST service (= Web service). /// diff --git a/TBF/Rig/TestMethods/GenesisCommunication/TestMethodCfgCtrl.cs b/TBF/Rig/TestMethods/GenesisCommunication/TestMethodCfgCtrl.cs index 1c86b0cf9..248682713 100644 --- a/TBF/Rig/TestMethods/GenesisCommunication/TestMethodCfgCtrl.cs +++ b/TBF/Rig/TestMethods/GenesisCommunication/TestMethodCfgCtrl.cs @@ -14,14 +14,14 @@ namespace TBF.Rig.TestMethods.GenesisCommunication { public bool ShowMore { get { return false; } } - iPerlCommunication.TestMethodCfg config; - public IComponentCfg Config + TestMethodCfg config; + public IComponentCfg Config { get { return config as IComponentCfg; } set { - config = value as iPerlCommunication.TestMethodCfg; - Redraw(); + config = value as TestMethodCfg; + Redraw(); } } diff --git a/TBF/Rig/TestMethods/GenesisCommunication/iPerlCommunicationParams.cs b/TBF/Rig/TestMethods/GenesisCommunication/iPerlCommunicationParams.cs index fa1cfd1f3..cc2dace83 100644 --- a/TBF/Rig/TestMethods/GenesisCommunication/iPerlCommunicationParams.cs +++ b/TBF/Rig/TestMethods/GenesisCommunication/iPerlCommunicationParams.cs @@ -27,12 +27,16 @@ namespace TBF.Rig.TestMethods.GenesisCommunication /// Communication activity public bool SimultWithPrevious; public bool SimultWithNext; + public string MeterSize = "DN50"; + public float Temperature = 20.0f; public override void InitializeAll() { Activity = GenesisCommunicationForm.SlotInitializeStr; SimultWithPrevious = false; SimultWithNext = false; + MeterSize = "DN50"; + Temperature = 20.0f; } @@ -41,6 +45,8 @@ namespace TBF.Rig.TestMethods.GenesisCommunication Strings.Activity, Strings.Simultaneous_with_previous_step, Strings.Simultaneous_with_next_step, + "Meter size", + "Temperature [°C]", }; public override string ParamName(int i) { return paramNames[i]; } public override int ParamsCount() { return paramNames.Length; } @@ -65,6 +71,14 @@ namespace TBF.Rig.TestMethods.GenesisCommunication retVal.Add(GenesisCommunicationForm.WriteSlotQ3CalibrationStr); retVal.Add(GenesisCommunicationForm.CheckMeterPrepareStr); retVal.Add(GenesisCommunicationForm.HoldSlotStr); + retVal.Add(GenesisCommunicationSeq.PreadjustmentInitializationStr); + retVal.Add(GenesisCommunicationSeq.PreadjustmentDetectStr); + retVal.Add(GenesisCommunicationSeq.PreadjustmentPreparationStr); + retVal.Add(GenesisCommunicationSeq.PreadjustmentAmplitudeTestStr); + retVal.Add(GenesisCommunicationSeq.PreadjustmentTemperatureCalibrationStr); + retVal.Add(GenesisCommunicationSeq.PreadjustmentPushTemperatureStr); + retVal.Add(GenesisCommunicationSeq.PreadjustmentOffsetTestStr); + retVal.Add(GenesisCommunicationSeq.PreadjustmentCompletionStr); @@ -126,10 +140,18 @@ namespace TBF.Rig.TestMethods.GenesisCommunication return retVal; } - else + else if (i == 1 || i == 2) { return new string[] { Strings.yes, Strings.no }; } + else if (i == 3) + { + var meterSizes = new List(System.Enum.GetNames(typeof(Xylem.Common.Logic.ProductionOrderCore.OrderData.MeterSize))); + meterSizes.Remove(Xylem.Common.Logic.ProductionOrderCore.OrderData.MeterSize.NA.ToString()); + return meterSizes; + } + + return null; } public override string ToString(int i) @@ -139,6 +161,8 @@ namespace TBF.Rig.TestMethods.GenesisCommunication case 0: return Activity; case 1: return (SimultWithPrevious ? Strings.yes : Strings.no); case 2: return (SimultWithNext ? Strings.yes : Strings.no); + case 3: return MeterSize; + case 4: return Temperature.ToString(); default: return string.Empty; } } @@ -150,6 +174,8 @@ namespace TBF.Rig.TestMethods.GenesisCommunication case 0: Activity = strValue; return CfgUpdateFlags.None; case 1: SimultWithPrevious = strValue.ToLower().Equals(Strings.yes.ToLower()); return CfgUpdateFlags.None; case 2: SimultWithNext = strValue.ToLower().Equals(Strings.yes.ToLower()); return CfgUpdateFlags.None; + case 3: MeterSize = strValue; return CfgUpdateFlags.None; + case 4: Temperature = Utils.ParseSFloat(strValue); return CfgUpdateFlags.None; default: return CfgUpdateFlags.None; } } @@ -157,6 +183,7 @@ namespace TBF.Rig.TestMethods.GenesisCommunication public bool ValidateParam(int i, string strValue, out string message) { message = string.Empty; + float temperature; switch (i) { @@ -166,6 +193,11 @@ namespace TBF.Rig.TestMethods.GenesisCommunication case 2: if (strValue.Equals(Strings.yes) || strValue.Equals(Strings.no)) return true; break; + case 3: + return System.Enum.TryParse(strValue, true, out Xylem.Common.Logic.ProductionOrderCore.OrderData.MeterSize meterSize) && meterSize != Xylem.Common.Logic.ProductionOrderCore.OrderData.MeterSize.NA; + case 4: + if (Utils.TryParseSFloat(strValue, out temperature) && temperature >= -20.0f && temperature <= 100.0f) return true; + break; default: message = "Invalid index"; return false; @@ -180,6 +212,8 @@ namespace TBF.Rig.TestMethods.GenesisCommunication prms.Activity = this.Activity; prms.SimultWithPrevious = this.SimultWithPrevious; prms.SimultWithNext = this.SimultWithNext; + prms.MeterSize = this.MeterSize; + prms.Temperature = this.Temperature; } public IParamsProvider Clone()