From ad2bfd3639e9c9e71d73874082d3ea6877b5d6b6 Mon Sep 17 00:00:00 2001 From: Marek Frniak Date: Thu, 14 May 2026 13:05:21 +0200 Subject: [PATCH 1/4] Upgrade (develop) - GCI - GciBridge - improved Disconnect --- .../API/InterfaceGCIToLaatzen.cs | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/GenesisCordonelInterface/API/InterfaceGCIToLaatzen.cs b/GenesisCordonelInterface/API/InterfaceGCIToLaatzen.cs index 85db1aebd..1c18161a7 100644 --- a/GenesisCordonelInterface/API/InterfaceGCIToLaatzen.cs +++ b/GenesisCordonelInterface/API/InterfaceGCIToLaatzen.cs @@ -75,7 +75,10 @@ namespace GenesisCordonelInterface.API #endregion #region ================================== MeterBatch Debug ================================== - + /// + /// + /// + /// public List GetMeterBatchDebugStatuses() { List meters; @@ -942,9 +945,17 @@ namespace GenesisCordonelInterface.API var meter = GetMeterThreadSafe(slot); - meter.Logout(); + bool logoutSuccess = meter.Logout(); meter.Disconnect(); + if (meter.IsLoggedOn) + { + meter.MarkLoggedOut(); + meter.LastLogoutStatus = logoutSuccess + ? "Successfully logged out" + : "Logout failed, but connection was closed"; + } + bool success = !meter.IsConnected && !meter.IsLoggedOn; if (success) From ad208f9633641cedddf29539f8e8f452d8910faa Mon Sep 17 00:00:00 2001 From: Marek Frniak Date: Mon, 18 May 2026 19:20:10 +0200 Subject: [PATCH 2/4] Develop - GciBridge -> GCI -> PreadjustmentUI functions --- .../API/InterfaceGCIToLaatzen.cs | 397 +++++++++++++++++- .../API/InterfaceOutsideToGCI.cs | 33 +- .../FrmCordonelPreadjustmentUI.cs | 160 ++++++- .../PreAdjustmentControl.cs | 98 ++++- .../BridgeComponents/GciBridge/GciBridge.cs | 98 ++++- .../GciBridge/UI/MainView.Designer.cs | 96 +++-- .../BridgeComponents/GciBridge/UI/MainView.cs | 353 +++++++--------- ...ner.cs => CombinedActionsView.Designer.cs} | 2 +- ...nterfaceView.cs => CombinedActionsView.cs} | 4 +- ...faceView.resx => CombinedActionsView.resx} | 0 .../PreadjustmentActionsView.Designer.cs | 271 ++++++++++++ .../PreadjustmentActionsView.cs | 338 +++++++++++++++ ...iew.resx => PreadjustmentActionsView.resx} | 0 ...sComPortsRegistersActionsView.Designer.cs} | 2 +- ...s => SlotsComPortsRegistersActionsView.cs} | 4 +- ...=> SlotsComPortsRegistersActionsView.resx} | 0 ...s => UniDataSorageActionsView.Designer.cs} | 49 +-- ...aceView.cs => UniDataSorageActionsView.cs} | 4 +- .../UniDataSorageActionsView.resx | 120 ++++++ TBF/TBF.csproj | 47 ++- 20 files changed, 1771 insertions(+), 305 deletions(-) rename TBF/Rig/BridgeComponents/GciBridge/UI/StaraTuraAPI_GciBridge/{CombinedInterfaceView.Designer.cs => CombinedActionsView.Designer.cs} (99%) rename TBF/Rig/BridgeComponents/GciBridge/UI/StaraTuraAPI_GciBridge/{CombinedInterfaceView.cs => CombinedActionsView.cs} (98%) rename TBF/Rig/BridgeComponents/GciBridge/UI/StaraTuraAPI_GciBridge/{CombinedInterfaceView.resx => CombinedActionsView.resx} (100%) create mode 100644 TBF/Rig/BridgeComponents/GciBridge/UI/StaraTuraAPI_GciBridge/PreadjustmentActionsView.Designer.cs create mode 100644 TBF/Rig/BridgeComponents/GciBridge/UI/StaraTuraAPI_GciBridge/PreadjustmentActionsView.cs rename TBF/Rig/BridgeComponents/GciBridge/UI/StaraTuraAPI_GciBridge/{GenesisCordonelInterfaceView.resx => PreadjustmentActionsView.resx} (100%) rename TBF/Rig/BridgeComponents/GciBridge/UI/StaraTuraAPI_GciBridge/{GenesisCordonelInterfaceView.Designer.cs => SlotsComPortsRegistersActionsView.Designer.cs} (99%) rename TBF/Rig/BridgeComponents/GciBridge/UI/StaraTuraAPI_GciBridge/{GenesisCordonelInterfaceView.cs => SlotsComPortsRegistersActionsView.cs} (99%) rename TBF/Rig/BridgeComponents/GciBridge/UI/StaraTuraAPI_GciBridge/{UniDataStorageReaderInterfaceView.resx => SlotsComPortsRegistersActionsView.resx} (100%) rename TBF/Rig/BridgeComponents/GciBridge/UI/StaraTuraAPI_GciBridge/{UniDataStorageReaderInterfaceView.Designer.cs => UniDataSorageActionsView.Designer.cs} (96%) rename TBF/Rig/BridgeComponents/GciBridge/UI/StaraTuraAPI_GciBridge/{UniDataStorageReaderInterfaceView.cs => UniDataSorageActionsView.cs} (94%) create mode 100644 TBF/Rig/BridgeComponents/GciBridge/UI/StaraTuraAPI_GciBridge/UniDataSorageActionsView.resx diff --git a/GenesisCordonelInterface/API/InterfaceGCIToLaatzen.cs b/GenesisCordonelInterface/API/InterfaceGCIToLaatzen.cs index 1c18161a7..b451d1ad7 100644 --- a/GenesisCordonelInterface/API/InterfaceGCIToLaatzen.cs +++ b/GenesisCordonelInterface/API/InterfaceGCIToLaatzen.cs @@ -1,4 +1,9 @@ -using GenesisCordonelInterface.Core.Threading; +using CordonelPreadjustmentUi; +using CordonelPreadjustmentUi.Processes; +using CordonelPreadjustmentUi.Processes.Actions; +using CordonelPreadjustmentUi.Processes.Itinerary; +using GenesisCordonelInterface.Core.Threading; +using GenesisCordonelInterface.UI.LaatzenAPI_CordonelPreadjustmentUI; using NLog; using NLog.Fluent; using System; @@ -17,6 +22,7 @@ using Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore; using Xylem.Common.Hardware.WaterMeter.Genesis.Registers; using Xylem.Common.Hardware.WaterMeter.WaterMeterCore; using Xylem.Common.Hardware.WaterMeter.WaterMeterRegisters; +using Xylem.Common.Ui.CordonelPreadjustmentUi; using static GenesisCordonelInterface.API.PublicModels; using static Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore.GenesisMeter; using static Xylem.Common.Hardware.WaterMeter.Genesis.Registers.Register; @@ -30,8 +36,14 @@ namespace GenesisCordonelInterface.API //private static readonly Lazy Logger = new Lazy(() => LogManager.GetLogger("GCI")); private static readonly NLog.ILogger Logger = NLog.LogManager.GetLogger("GenesisCordonelInterface"); + //GenesisToolBox private readonly MeterBatch _meterBatch = new MeterBatch(); + //Preadjustment + public PreAdjustmentSettingsContainer _settings = new PreAdjustmentSettingsContainer(); + public List _meterControls = new List(); + public List _tempMeterControls = new List(); + // Protects all access to _meterBatch.ListOfMeters private readonly object _meterBatchLock = new object(); private static readonly object _setupGenesisMeterLock = new object(); @@ -1381,5 +1393,388 @@ namespace GenesisCordonelInterface.API } #endregion + + // GCI to PreadjustmentUI - MANUAL - Laatzen GUI + + #region ================================== PreAdjustmentUI form call ================================== + + private FrmCordonelPreadjustmentUI _preadjustmentForm; + private readonly object _formLock = new object(); + + public event EventHandler PreadjustmentFormClosedByUser; + + /// + /// Shows singleton instance of preadjustment form. + /// + /// Behavior: + /// + /// ShowPreadjustmentForm() + /// ↓ + /// create form instance if necessary + /// ↓ + /// user works with form + /// ↓ + /// user clicks X + /// ↓ + /// FormClosing + /// ↓ + /// Cancel closing + /// ↓ + /// Hide() + /// ↓ + /// PreadjustmentFormClosedByUser + /// ↓ + /// external workflow continues + /// + /// Notes: + /// - form instance is reused + /// - form is hidden instead of disposed + /// - event notification is non-blocking + /// - repeated calls bring existing form to front + /// - actual disposal happens only during application shutdown + /// + /// Typical usage: + /// + /// _bridge.PreadjustmentFormClosedByUser += (s,e)=> + /// { + /// ContinueWorkflow(); + /// }; + /// + /// _bridge.ShowPreadjustmentForm(this); + /// + /// + public void ShowPreadjustmentForm(IWin32Window owner) + { + lock (_formLock) + { + // Create form only if it does not exist + // or has already been disposed + if (_preadjustmentForm == null || _preadjustmentForm.IsDisposed) + { + _preadjustmentForm = new FrmCordonelPreadjustmentUI(_meterBatch); + + _preadjustmentForm.FormClosing += (s, e) => + { + // Hide the form instead of destroying it + // when user clicks the close button + if (e.CloseReason == CloseReason.UserClosing) + { + e.Cancel = true; + _preadjustmentForm.Hide(); + + // Notify outside code that the form was closed by user + PreadjustmentFormClosedByUser?.Invoke( + this, + EventArgs.Empty); + } + }; + } + + // If already visible, bring it to front + if (_preadjustmentForm.Visible) + { + _preadjustmentForm.Activate(); + _preadjustmentForm.BringToFront(); + return; + } + + // Show existing form instance + _preadjustmentForm.Show(owner); + } + } + + #endregion + + #region ================================== Create context for PreAdjustmentUI ================================== + + /*public interface IGciToolContext + { + IReadOnlyList GetEnabledSlots(); + + string GetPcbId(int slot); + string GetSerialNumber(int slot); + + bool Login(int slot); + bool Logout(int slot); + + bool ReadRegister(int slot, int address, out string value); + bool WriteRegister(int slot, int address, string value); + + void LogInfo(string message); + void LogError(string message); + + event EventHandler MeterChanged; + }*/ + + + #endregion + + // GCI to PreadjustmentUI - AUTOMATIC - STANDALONE - Laatzen GUI + + #region ================================== PreAdjustmentUI DETECT process ================================== + + public Task Preadjustment_DetectAsync( + CancellationToken token = default) + { + return Task.Run(() => Preadjustment_DetectCore( + token), + token); + } + + private bool Preadjustment_DetectCore( + CancellationToken token) + { + MeterBatch globalMeterBatch = new MeterBatch(); + MeterBatch thermoMeterBatch = new MeterBatch(); + + if (globalMeterBatch == null) + throw new ArgumentNullException(nameof(globalMeterBatch)); + + if (thermoMeterBatch == null) + throw new ArgumentNullException(nameof(thermoMeterBatch)); + + if (_settings == null) + throw new ArgumentNullException(nameof(_settings)); + + if (_meterControls == null) + throw new ArgumentNullException(nameof(_meterControls)); + + if (_tempMeterControls == null) + _tempMeterControls = new List(); + + // Clear previous batch content + if (globalMeterBatch.ListOfMeters.Any()) + globalMeterBatch.RemoveAllMeters(); + + if (thermoMeterBatch.ListOfMeters.Any()) + thermoMeterBatch.RemoveAllMeters(); + + globalMeterBatch = _meterBatch; + + // If manual temperature input is used, + // ignore temporary meter controls + if (!_settings.GetTempUseTempFlansh()) + _tempMeterControls.Clear(); + + var allMeterControls = + new List(); + + allMeterControls.AddRange(_meterControls); + allMeterControls.AddRange(_tempMeterControls); + + CreateZeroFlowMeters(globalMeterBatch, thermoMeterBatch, allMeterControls, token); + + SetEnableOpeningState(allMeterControls); + + if (!_meterControls.Any(a => a.EnableOpening)) + return false; + + SetUnknownStatus(allMeterControls); + + //CheckNormalMeters( meterControls, token); //open ports + + CheckTemperatureMeters(_settings, _tempMeterControls, token); + + return true; + } + + private void CreateZeroFlowMeters( + MeterBatch globalMeterBatch, + MeterBatch thermoMeterBatch, + List allMeterControls, + CancellationToken token) + { + foreach (var meterStateCtl in allMeterControls) + { + token.ThrowIfCancellationRequested(); + + if (!(meterStateCtl.IsEnabled || + meterStateCtl is TempMeterStateControl)) + { + continue; + } + + if (meterStateCtl.Slot == -1) + continue; + + ZeroFlowGenesisMeter currentMeter = new ZeroFlowGenesisMeter(meterStateCtl.Slot, 3, !(meterStateCtl is TempMeterStateControl)); + + var convertedMeter = GetMeterThreadSafe(meterStateCtl.Slot); + if (convertedMeter != null) + { + convertedMeter.CopySafeStateTo(currentMeter); + } + + currentMeter.LogOnEnable = true; + currentMeter.LoginFailed = false; + currentMeter.PreparationFailed = false; + currentMeter.AmplitudeFailed = false; + currentMeter.ZeroFlowOffsetFailed = false; + currentMeter.CompletionFailed = false; + currentMeter.Ok = false; + currentMeter.EmptyPipeCheckEnable = false; + currentMeter.EmptyPipeCheckFailed = false; + + if (meterStateCtl is TempMeterStateControl) + { + thermoMeterBatch.AddMeter(currentMeter); + meterStateCtl.IsEnabled = true; + } + else + { + if (currentMeter.useConfigSource != ConfigSource.InterfaceInputConfig) + globalMeterBatch.AddMeter(currentMeter); + else + globalMeterBatch.AddMeter2(currentMeter); + } + + meterStateCtl.Meter = currentMeter; + } + } + + private void SetEnableOpeningState( + List allMeterControls) + { + foreach (var meterState in allMeterControls) + { + meterState.EnableOpening = + meterState.IsEnabled; + } + } + + private void SetUnknownStatus( + List allMeterControls) + { + foreach (var meterState in allMeterControls) + { + meterState.SetToUnknownStatus = + !meterState.EnableOpening; + } + } + + private void CheckNormalMeters( + List meterControls, + CancellationToken token) + { + foreach (var meterCtl in meterControls) + { + token.ThrowIfCancellationRequested(); + + if (meterCtl != null && meterCtl.IsEnabled) + { + meterCtl.Ok = + meterCtl.Meter.CheckRequestPort() && + meterCtl.Meter.CheckStreamingPort(); + } + } + } + + private void CheckTemperatureMeters( + PreAdjustmentSettingsContainer settings, + List tempMeterControls, + CancellationToken token) + { + if (settings.GetTempUseManualInput()) + return; + + foreach (var meterCtl in tempMeterControls) + { + token.ThrowIfCancellationRequested(); + + if (meterCtl != null && meterCtl.IsEnabled) + { + meterCtl.Ok = + meterCtl.Meter.CheckStreamingPort(); + } + } + } + + #endregion + + #region ================================== PreAdjustmentUI PREPARATION process ================================== + + /// + /// Execute standalone preparation process. + /// + /// Flow: + /// + /// Create ProcessProgress + /// ↓ + /// Create PreparationProcess + /// ↓ + /// Start process + /// ↓ + /// Wait for completion + /// ↓ + /// Return result + /// + /// Notes: + /// - GUI independent + /// - reusable from GCI workflow + /// - supports SinglePath and MultiPath mode + /// + public Task Preadjustment_PreparationAsync( + ProcessProgress pp, + CancellationToken token = default) + { + IProcess process; + + if (pp.Setting.NumberOfPaths == 1) + { + process = + new SPPreparationProcess( + "Preparation Single", + PreAdjustmentControl.StatusPanelItems.Prepare, + PreAdjustmentControl.PredefinedMessages.WaitUntilPreparationFinished(pp.Setting.Culture), + PreAdjustmentControl.PredefinedMessages.PreparationFailed(pp.Setting.Culture), + 60); + } + else + { + process = + new PreparationProcess( + "Preparation", + PreAdjustmentControl.StatusPanelItems.Prepare, + PreAdjustmentControl.PredefinedMessages.WaitUntilPreparationFinished(pp.Setting.Culture), + PreAdjustmentControl.PredefinedMessages.PreparationFailed(pp.Setting.Culture), + 60); + } + + return ExecuteProcessAsync( + process, + pp, + token); + } + + #endregion + + #region ================================== PreAdjustmentUI process threading ================================== + + public async Task ExecuteProcessAsync( + IProcess process, + ProcessProgress pp, + CancellationToken token = default) + { + return await Task.Run(() => + { + pp.IsBusy = true; + + process.StartProcess( + pp, + _meterControls, + _tempMeterControls); + + while (pp.IsBusy && !token.IsCancellationRequested) + { + Thread.Sleep(50); + } + + return !_meterControls.Any( + m => m.IsEnabled && m.Failed); + + }, token); + } + + #endregion } } \ No newline at end of file diff --git a/GenesisCordonelInterface/API/InterfaceOutsideToGCI.cs b/GenesisCordonelInterface/API/InterfaceOutsideToGCI.cs index 3e57351e8..40b6bd4ab 100644 --- a/GenesisCordonelInterface/API/InterfaceOutsideToGCI.cs +++ b/GenesisCordonelInterface/API/InterfaceOutsideToGCI.cs @@ -1,8 +1,12 @@ -using System; +using CordonelPreadjustmentUi; +using CordonelPreadjustmentUi.Processes.Itinerary; +using System; using System.Collections.Generic; using System.IO.Ports; using System.Threading; using System.Threading.Tasks; +using Xylem.Common.Hardware.WaterMeter.WaterMeterCore; +using Xylem.Common.Ui.CordonelPreadjustmentUi; using static GenesisCordonelInterface.API.PublicModels; namespace GenesisCordonelInterface.API @@ -22,6 +26,8 @@ namespace GenesisCordonelInterface.API _innerMeterAPI = new InterfaceGCIToLaatzen(); } + // + #region ================================== PORT DETECTION ================================== public PortDetectionResult DetectStreamingPort(int slot) @@ -424,7 +430,6 @@ namespace GenesisCordonelInterface.API #endregion #region ================================== METER BATCH SETUP ================================== - // ---------------------------------------------------- public void ReloadSlotSetup() { @@ -438,12 +443,34 @@ namespace GenesisCordonelInterface.API RaiseMeterBatchStatusChanged(); } - // ---------------------------------------------------- #endregion + #region ================================== Register names ================================== + public List GetAllRegisterNames() { return _innerMeterAPI.GetAllRegisterNames(); } + + #endregion + + // Preadjustment + + public Task Preadjustment_DetectAsync( + CancellationToken token = default) + { + return _innerMeterAPI.Preadjustment_DetectAsync(token); + } + + public Task Preadjustment_PreparationAsync( + ProcessProgress pp, + CancellationToken token = default) + { + return _innerMeterAPI.Preadjustment_PreparationAsync( + pp, + token); + } + + } } \ No newline at end of file diff --git a/GenesisCordonelInterface/UI/LaatzenAPI_CordonelPreadjustmentUI/FrmCordonelPreadjustmentUI.cs b/GenesisCordonelInterface/UI/LaatzenAPI_CordonelPreadjustmentUI/FrmCordonelPreadjustmentUI.cs index 789fb9ae0..de79acc2f 100644 --- a/GenesisCordonelInterface/UI/LaatzenAPI_CordonelPreadjustmentUI/FrmCordonelPreadjustmentUI.cs +++ b/GenesisCordonelInterface/UI/LaatzenAPI_CordonelPreadjustmentUI/FrmCordonelPreadjustmentUI.cs @@ -1,4 +1,5 @@ -using Newtonsoft.Json; +using CordonelPreadjustmentUi; +using Newtonsoft.Json; using System; using System.Collections.Generic; using System.Drawing; @@ -10,18 +11,26 @@ using System.Windows.Forms; using Xylem.Common.CommonCore.Consts; using Xylem.Common.Hardware.Interfaces.Ports.PortCore; using Xylem.Common.Hardware.WaterMeter.Genesis.GenesisConfig; +using Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore; using Xylem.Common.Hardware.WaterMeter.WaterMeterCore; using Xylem.Common.Ui.CordonelPreadjustmentUi; -using CordonelPreadjustmentUi; +using static Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore.GenesisMeter; +using System.Linq;//...MF namespace GenesisCordonelInterface.UI.LaatzenAPI_CordonelPreadjustmentUI { public partial class FrmCordonelPreadjustmentUI : Form { - private PreAdjustmentControl preadjustCtl; + public PreAdjustmentControl preadjustCtl;//...MF private PreAdjustmentSettingsContainer mainSettings = new PreAdjustmentSettingsContainer(); + public MeterBatch _externMetersBatch; + public FrmCordonelPreadjustmentUI() { + } + public FrmCordonelPreadjustmentUI(MeterBatch externMetersBatch) + { + _externMetersBatch = externMetersBatch; InitializeComponent(); } @@ -29,7 +38,7 @@ namespace GenesisCordonelInterface.UI.LaatzenAPI_CordonelPreadjustmentUI { - preadjustCtl = new PreAdjustmentControl(mainSettings); + preadjustCtl = new PreAdjustmentControl(mainSettings, _externMetersBatch); tab_ZeroFlowCal.Controls.Add(preadjustCtl); @@ -71,7 +80,7 @@ namespace GenesisCordonelInterface.UI.LaatzenAPI_CordonelPreadjustmentUI { if (e.TabPage.Name == tab_ZeroFlowCal.Name) { - try + /*try { var _serialConfigFile = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "Genesis", ProgramConfig.SerialConfigFileName); @@ -99,11 +108,81 @@ namespace GenesisCordonelInterface.UI.LaatzenAPI_CordonelPreadjustmentUI catch (Exception ex) { MessageBox.Show($"use default meters because of {ex.Message}"); + }*/ + + try //...MF + { + mainSettings.Meters = new List(); + mainSettings.TempMeters = new List(); + + // ========================================== + // Try loading configuration from GCI meters + // ========================================== + + bool loadedFromInterface = false; + + if (_externMetersBatch != null && + _externMetersBatch.ListOfMeters.Any()) + { + foreach (GenesisMeter meter in _externMetersBatch.ListOfMeters) + { + // Skip meters that should use file configuration + if (meter.useConfigSource != ConfigSource.InterfaceInputConfig) + continue; + + loadedFromInterface = true; + + // Split normal and temperature meters + //if (meter.Type == SlotType.TemperatureMeter) + //{ + // mainSettings.TempMeters.Add(meter.Slot); + //} + //else + //{ + mainSettings.Meters.Add(meter.Slot); + //} + } + } + + // ========================================== + // Fallback to configuration file + // ========================================== + + if (!loadedFromInterface) + { + var _serialConfigFile = + Path.Combine( + Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), + "Genesis", + ProgramConfig.SerialConfigFileName); + + SlotConfig[] meterConfigList; + + using (var tr = new StreamReader(_serialConfigFile)) + { + var _fileString = tr.ReadToEnd(); + + meterConfigList = + JsonConvert.DeserializeObject(_fileString); + } + + foreach (var item in meterConfigList) + { + if (item.Type != SlotType.TemperatureMeter) + { + mainSettings.Meters.Add(item.Slot); + } + else + { + mainSettings.TempMeters.Add(item.Slot); + } + } + } + } + catch (Exception ex) + { + MessageBox.Show($"Use default meters because of {ex.Message}"); } - - - - mainSettings.NumberOfPaths = cB_SinglePath.Checked ? 1 : 3; mainSettings.LowerTempLimit = (double)nUD_SettingsTempMonitorLowerValue.Value; @@ -156,7 +235,7 @@ namespace GenesisCordonelInterface.UI.LaatzenAPI_CordonelPreadjustmentUI } - private void MainForm_FormClosing(object sender, FormClosingEventArgs e) + /*private void MainForm_FormClosing(object sender, FormClosingEventArgs e) { if (preadjustCtl != null) { @@ -177,7 +256,68 @@ namespace GenesisCordonelInterface.UI.LaatzenAPI_CordonelPreadjustmentUI } + }*/ + + /// + /// Raised when user closes the preadjustment window + /// using the window close button (X). + /// + /// Note: + /// Form is hidden, not disposed. + /// This event allows external code to continue + /// workflow asynchronously. + /// + public event EventHandler OnUserClosed; + + private void MainForm_FormClosing(object sender, FormClosingEventArgs e) + { + // User clicked X button - hide form only + if (e.CloseReason == CloseReason.UserClosing) + { + e.Cancel = true; + this.Hide(); + + OnUserClosed?.Invoke(this, EventArgs.Empty); + return; + } + + // Real application shutdown / dispose + DisposeResources(); } + + /// + /// Dispose all internal resources that should + /// only be released during real application shutdown. + /// + /// Do not call when form is hidden. + /// + private void DisposeResources() + { + if (preadjustCtl != null) + { + preadjustCtl.CloseConnections(); + preadjustCtl.Dispose(); + preadjustCtl = null; + } + + if (ThermoMeterBatch != null) + { + ThermoMeterBatch.Dispose(); + ThermoMeterBatch = null; + } + + if (TempMeterStateCtls != null) + { + foreach (var item in TempMeterStateCtls) + { + item.Dispose(); + } + + TempMeterStateCtls.Clear(); + TempMeterStateCtls = null; + } + } + private MeterBatch ThermoMeterBatch = new MeterBatch(); private List TempMeterStateCtls = new List(); private void tmpStart(int slot, bool RaspiMode = false) diff --git a/GenesisCordonelInterface/UI/LaatzenAPI_CordonelPreadjustmentUI/PreAdjustmentControl.cs b/GenesisCordonelInterface/UI/LaatzenAPI_CordonelPreadjustmentUI/PreAdjustmentControl.cs index bee46c25b..b63a0e73d 100644 --- a/GenesisCordonelInterface/UI/LaatzenAPI_CordonelPreadjustmentUI/PreAdjustmentControl.cs +++ b/GenesisCordonelInterface/UI/LaatzenAPI_CordonelPreadjustmentUI/PreAdjustmentControl.cs @@ -1,4 +1,5 @@ -using CordonelPreadjustmentUi.Processes; +using CordonelPreadjustmentUi; +using CordonelPreadjustmentUi.Processes; using CordonelPreadjustmentUi.Processes.Actions; using CordonelPreadjustmentUi.Processes.Itinerary; using System; @@ -6,16 +7,18 @@ using System.Collections.Generic; using System.Drawing; using System.Globalization; using System.Linq; +using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; using System.Windows.Forms; +using Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore; using Xylem.Common.Hardware.WaterMeter.WaterMeterCore; using Xylem.Common.Hardware.WaterMeter.WaterMeterCore.Consts; using Xylem.Common.Logic.ProductionOrderCore.OrderData; using Xylem.Common.Ui.CordonelPreadjustmentUi; using Xylem.Common.Ui.CordonelPreadjustmentUi.Parameters; -using CordonelPreadjustmentUi; +using static Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore.GenesisMeter; namespace GenesisCordonelInterface.UI { @@ -41,11 +44,18 @@ namespace GenesisCordonelInterface.UI private Boolean abortIndicator = false; public Boolean AbortIndicator { get { return abortIndicator; } set { abortIndicator = value; } } public int TestRunNumber; - public PreAdjustmentControl(PreAdjustmentSettingsContainer Settings = null) + public PreAdjustmentControl(PreAdjustmentSettingsContainer Settings = null, MeterBatch externalMetersBatch = null)//...MF { InitializeComponent(); SetSettings(Settings); rTB_ZeroFlowCal.AutoSize = true; + + //...MF + // Use external batch only if supplied + if (externalMetersBatch != null) + { + GlobalMeterBatch = externalMetersBatch; + } } public void SetSettings(PreAdjustmentSettingsContainer Settings = null) { @@ -120,6 +130,49 @@ namespace GenesisCordonelInterface.UI } cb_Metersize.SelectedItem = setM; + //...MF + // Create UI controls for configured meter slots. + // + // Flow: + // + // settings.Meters + // ↓ + // create MeterStateControl + // ↓ + // position control in UI + // ↓ + // check whether slot exists in externally supplied MeterBatch + // ↓ + // automatically enable corresponding checkbox + // ↓ + // register UI events + // ↓ + // add control into internal collection and group box + // + // Notes: + // - allows external GCI workflow to preselect meters + // - keeps UI synchronized with externally injected MeterBatch + // - slots contained in GlobalMeterBatch are automatically checked + // + foreach (var Meter in settings.Meters) + { + var ctl = new MeterStateControl(Meter); + ctl.Location = new Point(5 + ((tmpI - 1) * ctl.Width), 15); + + // Check meter if it exists in external MeterBatch + if (GlobalMeterBatch != null && + GlobalMeterBatch.ListOfMeters != null && + GlobalMeterBatch.ListOfMeters.Any(m => m.Slot == Meter)) + { + ctl.SetChecked(true); + } + + MeterStateCtls.Add(ctl); + gB_Meters.Controls.Add(ctl); + ctl.OnRequestDetails += Ctl_MouseEnter; + tmpI = tmpI + 1; + } + } } @@ -1694,13 +1747,46 @@ namespace GenesisCordonelInterface.UI List listOfProgrammParts = new List(); + //...MF + bool requiresInternalLoginFlow = true; + requiresInternalLoginFlow = + GlobalMeterBatch.ListOfMeters.All( + m => + { + var meter = m as GenesisMeter; + return meter == null || + meter.usePasswordSource != + PasswordSource.InterfaceInputPassword; + }); - listOfProgrammParts.Add(new PrepareTestProcess("PrepareTest", CordonelPreadjustmentUi.PreAdjustmentControl.StatusPanelItems.Detect, string.Empty, string.Empty, 1 * 60)); + //...MF + bool requiresInternalConfigFlow = true; + requiresInternalConfigFlow = + GlobalMeterBatch.ListOfMeters.All( + m => + { + var meter = m as GenesisMeter; - listOfProgrammParts.Add(new LoginProcess("Login", CordonelPreadjustmentUi.PreAdjustmentControl.StatusPanelItems.Detect, PredefinedMessages.WaitUntilLoginFinished(pp.Setting.Culture), PredefinedMessages.LoginFailed(pp.Setting.Culture), 1 * 60)); + return meter == null || + meter.useConfigSource != + ConfigSource.InterfaceInputConfig; + }); - listOfProgrammParts.Add(new FlushProcess("First Flush", CordonelPreadjustmentUi.PreAdjustmentControl.StatusPanelItems.Detect, PredefinedMessages.WaitUntilFlushFinished(pp.Setting.Culture), string.Empty, 2 * 60)); + if (requiresInternalConfigFlow)//...MF + { + listOfProgrammParts.Add(new PrepareTestProcess("PrepareTest", CordonelPreadjustmentUi.PreAdjustmentControl.StatusPanelItems.Detect, string.Empty, string.Empty, 1 * 60)); + } + + if (requiresInternalLoginFlow)//...MF + { + listOfProgrammParts.Add(new LoginProcess("Login", CordonelPreadjustmentUi.PreAdjustmentControl.StatusPanelItems.Detect, PredefinedMessages.WaitUntilLoginFinished(pp.Setting.Culture), PredefinedMessages.LoginFailed(pp.Setting.Culture), 1 * 60)); + } + + if (requiresInternalConfigFlow)//...MF + { + listOfProgrammParts.Add(new FlushProcess("First Flush", CordonelPreadjustmentUi.PreAdjustmentControl.StatusPanelItems.Detect, PredefinedMessages.WaitUntilFlushFinished(pp.Setting.Culture), string.Empty, 2 * 60)); + } //listOfProgrammParts.Add(new PressureTestProcess("PreussureTest", StatusPanelItems.Prepare, PredefinedMessages.WaitUntilPreparationFinished(pp.Setting.Culture), PredefinedMessages.PreparationFailed(pp.Setting.Culture), 1 * 60)); diff --git a/TBF/Rig/BridgeComponents/GciBridge/GciBridge.cs b/TBF/Rig/BridgeComponents/GciBridge/GciBridge.cs index 15e48586f..48403914b 100644 --- a/TBF/Rig/BridgeComponents/GciBridge/GciBridge.cs +++ b/TBF/Rig/BridgeComponents/GciBridge/GciBridge.cs @@ -1,4 +1,7 @@ -using GenesisCordonelInterface.API; +using CordonelPreadjustmentUi; +using CordonelPreadjustmentUi.Processes.Itinerary; +using GenesisCordonelInterface.API; +using GenesisCordonelInterface.Core.Threading; using log4net; /// /// Copyright (c) 2015-2021 Sensus Slovensko a.s. @@ -13,6 +16,8 @@ using TBF.Rig.BridgeComponents.GciBridge.UI; using TBF.Rig.Generic; using TBF.Rig.Input.DataStorage.UniDataStorageReader; using TBF.Rig.Input.DataStorage.UniDataStorageReader.Searching.Database; +using Xylem.Common.Hardware.WaterMeter.WaterMeterCore; +using Xylem.Common.Ui.CordonelPreadjustmentUi; using static TBF.Rig.BridgeComponents.GciBridge.Interfaces.PublicModels; using GciGUIType = GenesisCordonelInterface.UI.MainView; using GciPublicModels = GenesisCordonelInterface.API.PublicModels; @@ -20,7 +25,6 @@ using GciType = GenesisCordonelInterface.API.InterfaceOutsideToGCI; using UdsReaderType = TBF.Rig.Input.DataStorage.UniDataStorageReader.Reader; using UDSRPublicModels = TBF.Rig.Input.DataStorage.UniDataStorageReader.Interfaces.PublicModels; using UdsWriterType = TBF.Rig.Output.DataStorage.UniDataStorageWriter.Writer; -using GenesisCordonelInterface.Core.Threading; namespace TBF.Rig.BridgeComponents.GciBridge { @@ -47,8 +51,8 @@ namespace TBF.Rig.BridgeComponents.GciBridge Form gciGuiHostForm; //diag GUI for GciBridge - public UserControl gciBridgeGUI; - public MainForm gciBridgeGuiForm; + public UserControl gciBridgeGUIUserControl; + public UI.MainForm gciBridgeGuiForm; public GciType gciExternalInterface; @@ -119,7 +123,7 @@ namespace TBF.Rig.BridgeComponents.GciBridge if (gciBridgeGuiForm != null && !gciBridgeGuiForm.IsDisposed) return; - gciBridgeGuiForm = new MainForm(this); + gciBridgeGuiForm = new UI.MainForm(this); gciBridgeGuiForm.Text = "Gci Bridge GUI"; gciBridgeGuiForm.Width = 1300; gciBridgeGuiForm.Height = 600; @@ -1417,6 +1421,90 @@ namespace TBF.Rig.BridgeComponents.GciBridge #endregion + // Preadjustment API: + + #region ================================== Preadjustment DETECT bridge ================================== + + public async Task Preadjustment_DetectAsync( + CancellationToken token = default) + { + const string operation = nameof(Preadjustment_DetectAsync); + + try + { + EnsureExternalInterface(); + + log.InfoFormat("{0}: {1} Start.", Name, operation); + + bool result = + await gciExternalInterface.Preadjustment_DetectAsync( + token) + .ConfigureAwait(false); + + log.InfoFormat( + "{0}: {1} Finish. Success={2}", + Name, + operation, + result); + + return result; + } + catch (Exception ex) + { + log.Error( + string.Format("{0}: {1} failed.", Name, operation), + ex); + + return false; + } + } + + #endregion + + #region ================================== PreAdjustment PREPARATION bridge ================================== + + public async Task Preadjustment_PreparationAsync( + ProcessProgress pp, + CancellationToken token = default) + { + const string operation = nameof(Preadjustment_PreparationAsync); + + try + { + EnsureExternalInterface(); + + if (pp == null) + throw new ArgumentNullException(nameof(pp)); + + log.InfoFormat("{0}: {1} Start.", Name, operation); + + bool result = + await gciExternalInterface + .Preadjustment_PreparationAsync( + pp, + token) + .ConfigureAwait(false); + + log.InfoFormat( + "{0}: {1} Finish. Success={2}", + Name, + operation, + result); + + return result; + } + catch (Exception ex) + { + log.Error( + string.Format("{0}: {1} failed.", Name, operation), + ex); + + return false; + } + } + + #endregion + #region ======================================= Helpers ======================================= private UDSRPublicModels.DataQuery CreatePasswordQuery(string pcbId) { diff --git a/TBF/Rig/BridgeComponents/GciBridge/UI/MainView.Designer.cs b/TBF/Rig/BridgeComponents/GciBridge/UI/MainView.Designer.cs index b91caceed..86d9058c0 100644 --- a/TBF/Rig/BridgeComponents/GciBridge/UI/MainView.Designer.cs +++ b/TBF/Rig/BridgeComponents/GciBridge/UI/MainView.Designer.cs @@ -25,7 +25,7 @@ private System.Windows.Forms.Button btnRegisterStore; private System.Windows.Forms.Button btnPulseSetup; private System.Windows.Forms.Button preadjustmentButton; - private System.Windows.Forms.Button btnMetersAction; + private System.Windows.Forms.Button slotsComPortsRegistersActionsViewButton; private System.Windows.Forms.SplitContainer splitWorkArea; private System.Windows.Forms.Panel pnlGciViewHost; @@ -43,9 +43,11 @@ this.btnRegisterStore = new System.Windows.Forms.Button(); this.tabPage2 = new System.Windows.Forms.TabPage(); this.groupBox5 = new System.Windows.Forms.GroupBox(); - this.btnMetersAction = new System.Windows.Forms.Button(); - this.storageActionButton = new System.Windows.Forms.Button(); - this.combinedActionButton = new System.Windows.Forms.Button(); + this.ScenariousViewButton = new System.Windows.Forms.Button(); + this.preadjustmenActionsViewButton = new System.Windows.Forms.Button(); + this.slotsComPortsRegistersActionsViewButton = new System.Windows.Forms.Button(); + this.uniDataSorageActionsViewButton = new System.Windows.Forms.Button(); + this.combinedActionsViewButton = new System.Windows.Forms.Button(); this.groupBox3 = new System.Windows.Forms.GroupBox(); this.btnDiagTablesConfigurationButton = new System.Windows.Forms.Button(); this.pnlMain = new System.Windows.Forms.Panel(); @@ -104,7 +106,6 @@ // this.tabPage1.Controls.Add(this.groupBox2); this.tabPage1.Controls.Add(this.groupBox1); - this.tabPage1.Enabled = false; this.tabPage1.Location = new System.Drawing.Point(4, 22); this.tabPage1.Name = "tabPage1"; this.tabPage1.Padding = new System.Windows.Forms.Padding(3); @@ -189,45 +190,66 @@ // // groupBox5 // - this.groupBox5.Controls.Add(this.btnMetersAction); - this.groupBox5.Controls.Add(this.storageActionButton); - this.groupBox5.Controls.Add(this.combinedActionButton); + this.groupBox5.Controls.Add(this.ScenariousViewButton); + this.groupBox5.Controls.Add(this.preadjustmenActionsViewButton); + this.groupBox5.Controls.Add(this.slotsComPortsRegistersActionsViewButton); + this.groupBox5.Controls.Add(this.uniDataSorageActionsViewButton); + this.groupBox5.Controls.Add(this.combinedActionsViewButton); this.groupBox5.Location = new System.Drawing.Point(6, 85); this.groupBox5.Name = "groupBox5"; - this.groupBox5.Size = new System.Drawing.Size(166, 131); + this.groupBox5.Size = new System.Drawing.Size(166, 202); this.groupBox5.TabIndex = 3; this.groupBox5.TabStop = false; - this.groupBox5.Text = "Interface"; + this.groupBox5.Text = "Interface testing"; // - // btnMetersAction + // ScenariousViewButton // - this.btnMetersAction.Location = new System.Drawing.Point(6, 19); - this.btnMetersAction.Name = "btnMetersAction"; - this.btnMetersAction.Size = new System.Drawing.Size(150, 30); - this.btnMetersAction.TabIndex = 1; - this.btnMetersAction.Text = "GenesisCordonelInterface"; - this.btnMetersAction.UseVisualStyleBackColor = true; - this.btnMetersAction.Click += new System.EventHandler(this.btnMetersAction_Click); + this.ScenariousViewButton.Location = new System.Drawing.Point(6, 163); + this.ScenariousViewButton.Name = "ScenariousViewButton"; + this.ScenariousViewButton.Size = new System.Drawing.Size(150, 30); + this.ScenariousViewButton.TabIndex = 3; + this.ScenariousViewButton.Text = "Scenarious"; + this.ScenariousViewButton.UseVisualStyleBackColor = true; // - // storageActionButton + // preadjustmenActionsViewButton // - this.storageActionButton.Location = new System.Drawing.Point(6, 55); - this.storageActionButton.Name = "storageActionButton"; - this.storageActionButton.Size = new System.Drawing.Size(150, 30); - this.storageActionButton.TabIndex = 0; - this.storageActionButton.Text = "UniDataStorageReader"; - this.storageActionButton.UseVisualStyleBackColor = true; - this.storageActionButton.Click += new System.EventHandler(this.button1_Click_1); + this.preadjustmenActionsViewButton.Location = new System.Drawing.Point(6, 127); + this.preadjustmenActionsViewButton.Name = "preadjustmenActionsViewButton"; + this.preadjustmenActionsViewButton.Size = new System.Drawing.Size(150, 30); + this.preadjustmenActionsViewButton.TabIndex = 2; + this.preadjustmenActionsViewButton.Text = "Preadjustment"; + this.preadjustmenActionsViewButton.UseVisualStyleBackColor = true; + this.preadjustmenActionsViewButton.Click += new System.EventHandler(this.preadjustmenActionsViewButton_Click); // - // combinedActionButton + // slotsComPortsRegistersActionsViewButton // - this.combinedActionButton.Location = new System.Drawing.Point(6, 91); - this.combinedActionButton.Name = "combinedActionButton"; - this.combinedActionButton.Size = new System.Drawing.Size(150, 30); - this.combinedActionButton.TabIndex = 0; - this.combinedActionButton.Text = "Combined Action"; - this.combinedActionButton.UseVisualStyleBackColor = true; - this.combinedActionButton.Click += new System.EventHandler(this.button2_Click); + this.slotsComPortsRegistersActionsViewButton.Location = new System.Drawing.Point(6, 19); + this.slotsComPortsRegistersActionsViewButton.Name = "slotsComPortsRegistersActionsViewButton"; + this.slotsComPortsRegistersActionsViewButton.Size = new System.Drawing.Size(150, 30); + this.slotsComPortsRegistersActionsViewButton.TabIndex = 1; + this.slotsComPortsRegistersActionsViewButton.Text = "Slots, ComPorts, Registers"; + this.slotsComPortsRegistersActionsViewButton.UseVisualStyleBackColor = true; + this.slotsComPortsRegistersActionsViewButton.Click += new System.EventHandler(this.btnMetersAction_Click); + // + // uniDataSorageActionsViewButton + // + this.uniDataSorageActionsViewButton.Location = new System.Drawing.Point(6, 55); + this.uniDataSorageActionsViewButton.Name = "uniDataSorageActionsViewButton"; + this.uniDataSorageActionsViewButton.Size = new System.Drawing.Size(150, 30); + this.uniDataSorageActionsViewButton.TabIndex = 0; + this.uniDataSorageActionsViewButton.Text = "UniDataStorageReader"; + this.uniDataSorageActionsViewButton.UseVisualStyleBackColor = true; + this.uniDataSorageActionsViewButton.Click += new System.EventHandler(this.button1_Click_1); + // + // combinedActionsViewButton + // + this.combinedActionsViewButton.Location = new System.Drawing.Point(6, 91); + this.combinedActionsViewButton.Name = "combinedActionsViewButton"; + this.combinedActionsViewButton.Size = new System.Drawing.Size(150, 30); + this.combinedActionsViewButton.TabIndex = 0; + this.combinedActionsViewButton.Text = "Combined actions"; + this.combinedActionsViewButton.UseVisualStyleBackColor = true; + this.combinedActionsViewButton.Click += new System.EventHandler(this.button2_Click); // // groupBox3 // @@ -386,9 +408,11 @@ this.ResumeLayout(false); } - private System.Windows.Forms.Button storageActionButton; + private System.Windows.Forms.Button uniDataSorageActionsViewButton; private System.Windows.Forms.GroupBox groupBox5; - private System.Windows.Forms.Button combinedActionButton; + private System.Windows.Forms.Button combinedActionsViewButton; private System.Windows.Forms.Button btnDiagTablesConfigurationButton; + private System.Windows.Forms.Button preadjustmenActionsViewButton; + private System.Windows.Forms.Button ScenariousViewButton; } } \ No newline at end of file diff --git a/TBF/Rig/BridgeComponents/GciBridge/UI/MainView.cs b/TBF/Rig/BridgeComponents/GciBridge/UI/MainView.cs index a0596d048..f1334d53f 100644 --- a/TBF/Rig/BridgeComponents/GciBridge/UI/MainView.cs +++ b/TBF/Rig/BridgeComponents/GciBridge/UI/MainView.cs @@ -72,58 +72,11 @@ namespace TBF.Rig.BridgeComponents.GciBridge.UI _uiLogFlushTimer.Interval = 250; _uiLogFlushTimer.Tick += UiLogFlushTimer_Tick; _uiLogFlushTimer.Start(); + + preadjustmentButton.Enabled = true; + groupBox2.Enabled = true; } - /// - /// Periodically flushes buffered log messages into RichTextBox. - /// - /// Runs on the UI thread because WinForms Timer executes on UI thread. - /// Processes messages in batches to reduce UI overhead. - /// - /// Plynule pridavanie do mema - /*private void UiLogFlushTimer_Tick(object sender, EventArgs e) - { - if (IsDisposed || !IsHandleCreated) - return; - - List messages = new List(); - - lock (_uiLogLock) - { - while (_pendingUiLogs.Count > 0 && messages.Count < 500) - { - messages.Add(_pendingUiLogs.Dequeue()); - } - } - - if (messages.Count == 0) - return; - - rtbMainLog.SuspendLayout(); - - try - { - foreach (string msg in messages) - { - AppendLogMessage(msg); - } - - const int maxTextLength = 200000; - - if (rtbMainLog.TextLength > maxTextLength) - { - rtbMainLog.Select(0, rtbMainLog.TextLength - maxTextLength); - rtbMainLog.SelectedText = ""; - } - - rtbMainLog.SelectionStart = rtbMainLog.TextLength; - rtbMainLog.ScrollToCaret(); - } - finally - { - rtbMainLog.ResumeLayout(); - } - }*/ private void UiLogFlushTimer_Tick(object sender, EventArgs e) { @@ -277,153 +230,6 @@ namespace TBF.Rig.BridgeComponents.GciBridge.UI base.Dispose(disposing); } - private IWin32Window DialogOwner - { - get - { - Form owner = FindForm(); - return owner ?? (IWin32Window)this; - } - } - - private void ShowGciView(Control view) - { - pnlGciViewHost.Controls.Clear(); - - view.Dock = DockStyle.Fill; - pnlGciViewHost.Controls.Add(view); - } - - /// - /// Saves current slot configuration from the grid into backend storage. - /// - public void SaveSlots() - { - var data = _batchPanel.GetGridData(); - _laatzenApi.SaveSlotSetup(data); - } - - /// - /// Switches currently displayed GCI view inside the host panel. - /// - private void button2_Click(object sender, EventArgs e) - { - SwitchGciView( - "CombinedInterfaceView", - new CombinedInterfaceView(this, _bridge)); - } - - private void button1_Click_1(object sender, EventArgs e) - { - SwitchGciView( - "StorageAction", - new UniDataStorageReaderInterfaceView(this, _bridge)); - } - - #region BUTTONS - - private void btnMetersAction_Click(object sender, EventArgs e) - { - SwitchGciView( - "SlotsMetersAction", - new GenesisCordonelInterfaceView(this, _bridge, AddSlotRow, SaveSlots)); - } - - private void btnSetup_Click(object sender, EventArgs e) - { - /*Logger.Trace("FORM: ---------------------------------"); - Logger.Trace("FORM: Setup open"); - - using (FrmSetup frm = new FrmSetup()) - { - frm.ShowDialog(DialogOwner); - } - - Logger.Trace("FORM: Setup closed.");*/ - } - - private void btnRegisterStore_Click(object sender, EventArgs e) - { - /*Logger.Trace("FORM: ---------------------------------"); - Logger.Trace("FORM: Register Store open."); - - using (FrmRegisterStore frm = new FrmRegisterStore()) - { - frm.ShowDialog(DialogOwner); - } - - Logger.Trace("FORM: Register Store closed.");*/ - } - - private void btnPulseSetup_Click(object sender, EventArgs e) - { - /*Logger.Trace("FORM: ---------------------------------"); - Logger.Trace("FORM: Pulse Setup open."); - - using (FrmConfigurations frm = new FrmConfigurations()) - { - frm.ShowDialog(DialogOwner); - } - - Logger.Trace("FORM: Pulse Setup closed.");*/ - } - - private void preadjustmentButton_Click(object sender, EventArgs e) - { - /*Logger.Trace("FORM: ---------------------------------"); - Logger.Trace("FORM: Preadjustment open."); - - using (FrmCordonelPreadjustmentUI frm = new FrmCordonelPreadjustmentUI()) - { - frm.ShowDialog(DialogOwner); - } - - Logger.Trace("FORM: Preadjustment closed.");*/ - } - - private void button1_Click(object sender, EventArgs e) - { - Logger.Trace("FORM: ---------------------------------"); - Logger.Trace("FORM: GciBridge GUI open."); - - using (var frm = new FrmGCIAPI(_gciApi)) - { - frm.ShowDialog(this); - } - - Logger.Trace("FORM: GciBridge closed."); - } - - private void SwitchGciView(string name, Control view) - { - Logger.Trace("FORM: ---------------------------------"); - Logger.Trace($"FORM: GciBridge VIEW -> {name} OPEN"); - - pnlGciViewHost.Controls.Clear(); - - view.Dock = DockStyle.Fill; - pnlGciViewHost.Controls.Add(view); - view.BringToFront(); - - Logger.Trace($"FORM: GciBridge VIEW -> {name} LOADED"); - } - - private void btnMeterInit_Click(object sender, EventArgs e) - { - SwitchGciView( - "MeterInit", - new MeterInitView(_gciApi, AddSlotRow, SaveSlots)); - } - - /// - /// Clears the main UI log window. - /// - public void ClearLog() - { - rtbMainLog.Clear(); - Logger.Trace("Log cleared."); - } - #endregion #region GLOBAL LOGGING to memo in this view @@ -545,11 +351,164 @@ namespace TBF.Rig.BridgeComponents.GciBridge.UI #endregion + private IWin32Window DialogOwner + { + get + { + Form owner = FindForm(); + return owner ?? (IWin32Window)this; + } + } + + private void ShowGciView(Control view) + { + pnlGciViewHost.Controls.Clear(); + + view.Dock = DockStyle.Fill; + pnlGciViewHost.Controls.Add(view); + } + + /// + /// Saves current slot configuration from the grid into backend storage. + /// + public void SaveSlots() + { + var data = _batchPanel.GetGridData(); + _laatzenApi.SaveSlotSetup(data); + } + + #region BUTTONS + + private void btnSetup_Click(object sender, EventArgs e) + { + /*Logger.Trace("FORM: ---------------------------------"); + Logger.Trace("FORM: Setup open"); + + using (FrmSetup frm = new FrmSetup()) + { + frm.ShowDialog(DialogOwner); + } + + Logger.Trace("FORM: Setup closed.");*/ + } + + private void btnRegisterStore_Click(object sender, EventArgs e) + { + /*Logger.Trace("FORM: ---------------------------------"); + Logger.Trace("FORM: Register Store open."); + + using (FrmRegisterStore frm = new FrmRegisterStore()) + { + frm.ShowDialog(DialogOwner); + } + + Logger.Trace("FORM: Register Store closed.");*/ + } + + private void btnPulseSetup_Click(object sender, EventArgs e) + { + /*Logger.Trace("FORM: ---------------------------------"); + Logger.Trace("FORM: Pulse Setup open."); + + using (FrmConfigurations frm = new FrmConfigurations()) + { + frm.ShowDialog(DialogOwner); + } + + Logger.Trace("FORM: Pulse Setup closed.");*/ + } + + private void preadjustmentButton_Click(object sender, EventArgs e) + { + Logger.Trace("FORM: ---------------------------------"); + Logger.Trace("FORM: Preadjustment open."); + + _laatzenApi.ShowPreadjustmentForm(DialogOwner); + + Logger.Trace("FORM: Preadjustment shown."); + } + + private void button1_Click(object sender, EventArgs e) + { + Logger.Trace("FORM: ---------------------------------"); + Logger.Trace("FORM: GciBridge GUI open."); + + using (var frm = new FrmGCIAPI(_gciApi)) + { + frm.ShowDialog(this); + } + + Logger.Trace("FORM: GciBridge closed."); + } + + private void SwitchGciView(string name, Control view) + { + Logger.Trace("FORM: ---------------------------------"); + Logger.Trace($"FORM: GciBridge VIEW -> {name} OPEN"); + + pnlGciViewHost.Controls.Clear(); + + view.Dock = DockStyle.Fill; + pnlGciViewHost.Controls.Add(view); + view.BringToFront(); + + Logger.Trace($"FORM: GciBridge VIEW -> {name} LOADED"); + } + + private void btnMeterInit_Click(object sender, EventArgs e) + { + SwitchGciView( + "MeterInit", + new MeterInitView(_gciApi, AddSlotRow, SaveSlots)); + } + + /// + /// Clears the main UI log window. + /// + public void ClearLog() + { + rtbMainLog.Clear(); + Logger.Trace("Log cleared."); + } + + /// + /// Switches currently displayed GCI view inside the host panel. + /// + private void button2_Click(object sender, EventArgs e) + { + SwitchGciView( + "CombinedActionsView", + new CombinedActionsView(this, _bridge)); + } + + private void button1_Click_1(object sender, EventArgs e) + { + SwitchGciView( + "UniDataSorageActionsView", + new UniDataSorageActionsView(this, _bridge)); + } + + private void btnMetersAction_Click(object sender, EventArgs e) + { + SwitchGciView( + "SlotsComPortsRegistersActionsView", + new SlotsComPortsRegistersActionsView(this, _bridge, AddSlotRow, SaveSlots)); + } + private void btnMeterInit_Click_1(object sender, EventArgs e) { SwitchGciView( "ConfigurationView", new ConfigurationView(this)); } + + private void preadjustmenActionsViewButton_Click(object sender, EventArgs e) + { + SwitchGciView( + "PreadjustmenActionsView", + new PreadjustmentActionsView(this, _bridge, AddSlotRow, SaveSlots)); + } } + + #endregion } \ No newline at end of file diff --git a/TBF/Rig/BridgeComponents/GciBridge/UI/StaraTuraAPI_GciBridge/CombinedInterfaceView.Designer.cs b/TBF/Rig/BridgeComponents/GciBridge/UI/StaraTuraAPI_GciBridge/CombinedActionsView.Designer.cs similarity index 99% rename from TBF/Rig/BridgeComponents/GciBridge/UI/StaraTuraAPI_GciBridge/CombinedInterfaceView.Designer.cs rename to TBF/Rig/BridgeComponents/GciBridge/UI/StaraTuraAPI_GciBridge/CombinedActionsView.Designer.cs index b295192e2..48b4667c5 100644 --- a/TBF/Rig/BridgeComponents/GciBridge/UI/StaraTuraAPI_GciBridge/CombinedInterfaceView.Designer.cs +++ b/TBF/Rig/BridgeComponents/GciBridge/UI/StaraTuraAPI_GciBridge/CombinedActionsView.Designer.cs @@ -1,6 +1,6 @@ namespace TBF.Rig.BridgeComponents.GciBridge.UI.StaraTuraAPI_GciBridge { - partial class CombinedInterfaceView + partial class CombinedActionsView { private System.ComponentModel.IContainer components = null; diff --git a/TBF/Rig/BridgeComponents/GciBridge/UI/StaraTuraAPI_GciBridge/CombinedInterfaceView.cs b/TBF/Rig/BridgeComponents/GciBridge/UI/StaraTuraAPI_GciBridge/CombinedActionsView.cs similarity index 98% rename from TBF/Rig/BridgeComponents/GciBridge/UI/StaraTuraAPI_GciBridge/CombinedInterfaceView.cs rename to TBF/Rig/BridgeComponents/GciBridge/UI/StaraTuraAPI_GciBridge/CombinedActionsView.cs index d20633c0c..45f95bb5a 100644 --- a/TBF/Rig/BridgeComponents/GciBridge/UI/StaraTuraAPI_GciBridge/CombinedInterfaceView.cs +++ b/TBF/Rig/BridgeComponents/GciBridge/UI/StaraTuraAPI_GciBridge/CombinedActionsView.cs @@ -10,7 +10,7 @@ using TBF.Rig.BridgeComponents.GciBridge.Interfaces; namespace TBF.Rig.BridgeComponents.GciBridge.UI.StaraTuraAPI_GciBridge { - public partial class CombinedInterfaceView : UserControl + public partial class CombinedActionsView : UserControl { private readonly MainView _mainView; private readonly GciBridge _bridge; @@ -19,7 +19,7 @@ namespace TBF.Rig.BridgeComponents.GciBridge.UI.StaraTuraAPI_GciBridge private readonly Dictionary _pcbBySlot = new Dictionary(); private readonly Dictionary _passwordBySlot = new Dictionary(); - public CombinedInterfaceView(MainView mainView, GciBridge bridge) + public CombinedActionsView(MainView mainView, GciBridge bridge) { _mainView = mainView ?? throw new ArgumentNullException(nameof(mainView)); _bridge = bridge ?? throw new ArgumentNullException(nameof(bridge)); diff --git a/TBF/Rig/BridgeComponents/GciBridge/UI/StaraTuraAPI_GciBridge/CombinedInterfaceView.resx b/TBF/Rig/BridgeComponents/GciBridge/UI/StaraTuraAPI_GciBridge/CombinedActionsView.resx similarity index 100% rename from TBF/Rig/BridgeComponents/GciBridge/UI/StaraTuraAPI_GciBridge/CombinedInterfaceView.resx rename to TBF/Rig/BridgeComponents/GciBridge/UI/StaraTuraAPI_GciBridge/CombinedActionsView.resx diff --git a/TBF/Rig/BridgeComponents/GciBridge/UI/StaraTuraAPI_GciBridge/PreadjustmentActionsView.Designer.cs b/TBF/Rig/BridgeComponents/GciBridge/UI/StaraTuraAPI_GciBridge/PreadjustmentActionsView.Designer.cs new file mode 100644 index 000000000..b08992b0c --- /dev/null +++ b/TBF/Rig/BridgeComponents/GciBridge/UI/StaraTuraAPI_GciBridge/PreadjustmentActionsView.Designer.cs @@ -0,0 +1,271 @@ +namespace TBF.Rig.BridgeComponents.GciBridge.UI.StaraTuraAPI_GciBridge +{ + partial class PreadjustmentActionsView + { + private System.ComponentModel.IContainer components = null; + + private System.Windows.Forms.GroupBox grpSlots; + + private System.Windows.Forms.Button preparationActionButton; + private System.Windows.Forms.Button btnUpdateSlot; + private System.Windows.Forms.Button detectActionButton; + private System.Windows.Forms.Button btnCleanAllSlots; + + private System.Windows.Forms.Button btnCancel; + private System.Windows.Forms.TextBox txtLog; + + protected override void Dispose(bool disposing) + { + if (disposing && components != null) + components.Dispose(); + + base.Dispose(disposing); + } + + private void InitializeComponent() + { + this.grpSlots = new System.Windows.Forms.GroupBox(); + this.writeRegisterNameComboBox = new System.Windows.Forms.ComboBox(); + this.readRegisterNameComboBox = new System.Windows.Forms.ComboBox(); + this.label4 = new System.Windows.Forms.Label(); + this.writeRegisterValueTextBox = new System.Windows.Forms.TextBox(); + this.label3 = new System.Windows.Forms.Label(); + this.label2 = new System.Windows.Forms.Label(); + this.writeRegisterButton = new System.Windows.Forms.Button(); + this.readRegisterButton = new System.Windows.Forms.Button(); + this.btnConnect = new System.Windows.Forms.Button(); + this.btnDisconnect = new System.Windows.Forms.Button(); + this.btnLogin = new System.Windows.Forms.Button(); + this.btnGetPcbId = new System.Windows.Forms.Button(); + this.preparationActionButton = new System.Windows.Forms.Button(); + this.btnUpdateSlot = new System.Windows.Forms.Button(); + this.detectActionButton = new System.Windows.Forms.Button(); + this.btnCleanAllSlots = new System.Windows.Forms.Button(); + this.btnCleanSlot = new System.Windows.Forms.Button(); + this.btnCancel = new System.Windows.Forms.Button(); + this.txtLog = new System.Windows.Forms.TextBox(); + this.grpSlots.SuspendLayout(); + this.SuspendLayout(); + // + // grpSlots + // + this.grpSlots.Controls.Add(this.writeRegisterNameComboBox); + this.grpSlots.Controls.Add(this.readRegisterNameComboBox); + this.grpSlots.Controls.Add(this.label4); + this.grpSlots.Controls.Add(this.writeRegisterValueTextBox); + this.grpSlots.Controls.Add(this.label3); + this.grpSlots.Controls.Add(this.label2); + this.grpSlots.Controls.Add(this.writeRegisterButton); + this.grpSlots.Controls.Add(this.readRegisterButton); + this.grpSlots.Controls.Add(this.btnConnect); + this.grpSlots.Controls.Add(this.btnDisconnect); + this.grpSlots.Controls.Add(this.btnLogin); + this.grpSlots.Controls.Add(this.btnGetPcbId); + this.grpSlots.Controls.Add(this.preparationActionButton); + this.grpSlots.Controls.Add(this.btnUpdateSlot); + this.grpSlots.Controls.Add(this.detectActionButton); + this.grpSlots.Controls.Add(this.btnCleanAllSlots); + this.grpSlots.Controls.Add(this.btnCleanSlot); + this.grpSlots.Location = new System.Drawing.Point(10, 10); + this.grpSlots.Name = "grpSlots"; + this.grpSlots.Size = new System.Drawing.Size(689, 304); + this.grpSlots.TabIndex = 2; + this.grpSlots.TabStop = false; + this.grpSlots.Text = "Slots by selection in the table"; + this.grpSlots.Enter += new System.EventHandler(this.grpSlots_Enter); + // + // writeRegisterNameComboBox + // + this.writeRegisterNameComboBox.FormattingEnabled = true; + this.writeRegisterNameComboBox.Location = new System.Drawing.Point(300, 264); + this.writeRegisterNameComboBox.Name = "writeRegisterNameComboBox"; + this.writeRegisterNameComboBox.Size = new System.Drawing.Size(213, 21); + this.writeRegisterNameComboBox.TabIndex = 15; + // + // readRegisterNameComboBox + // + this.readRegisterNameComboBox.FormattingEnabled = true; + this.readRegisterNameComboBox.Location = new System.Drawing.Point(300, 230); + this.readRegisterNameComboBox.Name = "readRegisterNameComboBox"; + this.readRegisterNameComboBox.Size = new System.Drawing.Size(213, 21); + this.readRegisterNameComboBox.TabIndex = 14; + // + // label4 + // + this.label4.AutoSize = true; + this.label4.Location = new System.Drawing.Point(224, 233); + this.label4.Name = "label4"; + this.label4.Size = new System.Drawing.Size(78, 13); + this.label4.TabIndex = 13; + this.label4.Text = "Register name:"; + // + // writeRegisterValueTextBox + // + this.writeRegisterValueTextBox.Location = new System.Drawing.Point(555, 264); + this.writeRegisterValueTextBox.Name = "writeRegisterValueTextBox"; + this.writeRegisterValueTextBox.Size = new System.Drawing.Size(117, 20); + this.writeRegisterValueTextBox.TabIndex = 12; + // + // label3 + // + this.label3.AutoSize = true; + this.label3.Location = new System.Drawing.Point(517, 267); + this.label3.Name = "label3"; + this.label3.Size = new System.Drawing.Size(36, 13); + this.label3.TabIndex = 10; + this.label3.Text = "value:"; + // + // label2 + // + this.label2.AutoSize = true; + this.label2.Location = new System.Drawing.Point(224, 267); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(78, 13); + this.label2.TabIndex = 9; + this.label2.Text = "Register name:"; + // + // writeRegisterButton + // + this.writeRegisterButton.Location = new System.Drawing.Point(15, 259); + this.writeRegisterButton.Name = "writeRegisterButton"; + this.writeRegisterButton.Size = new System.Drawing.Size(203, 28); + this.writeRegisterButton.TabIndex = 7; + this.writeRegisterButton.Text = "WriteRegister(slot, registerName, value)"; + this.writeRegisterButton.Click += new System.EventHandler(this.writeRegisterButton_Click); + // + // readRegisterButton + // + this.readRegisterButton.Location = new System.Drawing.Point(15, 225); + this.readRegisterButton.Name = "readRegisterButton"; + this.readRegisterButton.Size = new System.Drawing.Size(203, 28); + this.readRegisterButton.TabIndex = 6; + this.readRegisterButton.Text = "ReadRegister(slot, registerName)"; + // + // btnConnect + // + this.btnConnect.Location = new System.Drawing.Point(15, 158); + this.btnConnect.Name = "btnConnect"; + this.btnConnect.Size = new System.Drawing.Size(150, 28); + this.btnConnect.TabIndex = 3; + this.btnConnect.Text = "Connect(slot)"; + // + // btnDisconnect + // + this.btnDisconnect.Location = new System.Drawing.Point(15, 191); + this.btnDisconnect.Name = "btnDisconnect"; + this.btnDisconnect.Size = new System.Drawing.Size(150, 28); + this.btnDisconnect.TabIndex = 4; + this.btnDisconnect.Text = "Disconnect(slot)"; + // + // btnLogin + // + this.btnLogin.Location = new System.Drawing.Point(171, 158); + this.btnLogin.Name = "btnLogin"; + this.btnLogin.Size = new System.Drawing.Size(150, 28); + this.btnLogin.TabIndex = 17; + this.btnLogin.Text = "Login(slot)"; + // + // btnGetPcbId + // + this.btnGetPcbId.Location = new System.Drawing.Point(15, 125); + this.btnGetPcbId.Name = "btnGetPcbId"; + this.btnGetPcbId.Size = new System.Drawing.Size(150, 28); + this.btnGetPcbId.TabIndex = 5; + this.btnGetPcbId.Text = "GetPcb(slot)"; + // + // preparationActionButton + // + this.preparationActionButton.Location = new System.Drawing.Point(15, 25); + this.preparationActionButton.Name = "preparationActionButton"; + this.preparationActionButton.Size = new System.Drawing.Size(150, 28); + this.preparationActionButton.TabIndex = 0; + this.preparationActionButton.Text = "Preparation"; + this.preparationActionButton.Click += new System.EventHandler(this.preparationActionButton_Click); + // + // btnUpdateSlot + // + this.btnUpdateSlot.Location = new System.Drawing.Point(171, 25); + this.btnUpdateSlot.Name = "btnUpdateSlot"; + this.btnUpdateSlot.Size = new System.Drawing.Size(150, 28); + this.btnUpdateSlot.TabIndex = 16; + this.btnUpdateSlot.Text = "UpdateSlot(slot)"; + // + // detectActionButton + // + this.detectActionButton.Location = new System.Drawing.Point(15, 58); + this.detectActionButton.Name = "detectActionButton"; + this.detectActionButton.Size = new System.Drawing.Size(150, 28); + this.detectActionButton.TabIndex = 1; + this.detectActionButton.Text = "Detect"; + this.detectActionButton.Click += new System.EventHandler(this.detectActionButton_Click); + // + // btnCleanAllSlots + // + this.btnCleanAllSlots.Location = new System.Drawing.Point(171, 92); + this.btnCleanAllSlots.Name = "btnCleanAllSlots"; + this.btnCleanAllSlots.Size = new System.Drawing.Size(150, 28); + this.btnCleanAllSlots.TabIndex = 2; + this.btnCleanAllSlots.Text = "CleanAllSlots()"; + // + // btnCleanSlot + // + this.btnCleanSlot.Location = new System.Drawing.Point(15, 92); + this.btnCleanSlot.Name = "btnCleanSlot"; + this.btnCleanSlot.Size = new System.Drawing.Size(150, 28); + this.btnCleanSlot.TabIndex = 18; + this.btnCleanSlot.Text = "CleanSlot(slot)"; + // + // btnCancel + // + this.btnCancel.Enabled = false; + this.btnCancel.Location = new System.Drawing.Point(519, 320); + this.btnCancel.Name = "btnCancel"; + this.btnCancel.Size = new System.Drawing.Size(180, 30); + this.btnCancel.TabIndex = 4; + this.btnCancel.Text = "Cancel task"; + this.btnCancel.Click += new System.EventHandler(this.btnCancel_Click); + // + // txtLog + // + this.txtLog.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.txtLog.Location = new System.Drawing.Point(10, 356); + this.txtLog.Multiline = true; + this.txtLog.Name = "txtLog"; + this.txtLog.ReadOnly = true; + this.txtLog.ScrollBars = System.Windows.Forms.ScrollBars.Both; + this.txtLog.Size = new System.Drawing.Size(689, 232); + this.txtLog.TabIndex = 5; + this.txtLog.WordWrap = false; + // + // PreadjustmentActionsView + // + this.BackColor = System.Drawing.SystemColors.Control; + this.Controls.Add(this.grpSlots); + this.Controls.Add(this.btnCancel); + this.Controls.Add(this.txtLog); + this.Name = "PreadjustmentActionsView"; + this.Size = new System.Drawing.Size(719, 603); + this.grpSlots.ResumeLayout(false); + this.grpSlots.PerformLayout(); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + private System.Windows.Forms.Button btnConnect; + private System.Windows.Forms.Button btnDisconnect; + private System.Windows.Forms.Button btnGetPcbId; + private System.Windows.Forms.Button readRegisterButton; + private System.Windows.Forms.TextBox writeRegisterValueTextBox; + private System.Windows.Forms.Label label3; + private System.Windows.Forms.Label label2; + private System.Windows.Forms.Button writeRegisterButton; + private System.Windows.Forms.Label label4; + private System.Windows.Forms.ComboBox writeRegisterNameComboBox; + private System.Windows.Forms.ComboBox readRegisterNameComboBox; + private System.Windows.Forms.Button btnLogin; + private System.Windows.Forms.Button btnCleanSlot; + } +} \ No newline at end of file diff --git a/TBF/Rig/BridgeComponents/GciBridge/UI/StaraTuraAPI_GciBridge/PreadjustmentActionsView.cs b/TBF/Rig/BridgeComponents/GciBridge/UI/StaraTuraAPI_GciBridge/PreadjustmentActionsView.cs new file mode 100644 index 000000000..fbd1b728a --- /dev/null +++ b/TBF/Rig/BridgeComponents/GciBridge/UI/StaraTuraAPI_GciBridge/PreadjustmentActionsView.cs @@ -0,0 +1,338 @@ +using CordonelPreadjustmentUi; +using CordonelPreadjustmentUi.Processes.Itinerary; +using GenesisCordonelInterface.API; +using GenesisCordonelInterface.UI; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using System.Windows.Forms; +using Xylem.Common.Hardware.WaterMeter.WaterMeterCore; +using Xylem.Common.Ui.CordonelPreadjustmentUi; +using static Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore.PreadjustmentMeter; +using GciPublicModels = GenesisCordonelInterface.API.PublicModels; + +namespace TBF.Rig.BridgeComponents.GciBridge.UI.StaraTuraAPI_GciBridge +{ + public partial class PreadjustmentActionsView : UserControl + { + private readonly GciBridge _bridge; + private readonly MainView _mainView; + private CancellationTokenSource _cts; + private readonly Action _addSlotAction; + private readonly Action _saveAction; + + public PreadjustmentActionsView( + MainView mainview, + GciBridge bridge, + Action addSlotAction, + Action saveAction) + { + _mainView = mainview ?? throw new ArgumentNullException(nameof(mainview)); + _bridge = bridge ?? throw new ArgumentNullException(nameof(bridge)); + + _addSlotAction = addSlotAction; + _saveAction = saveAction; + + InitializeComponent(); + + LoadRegisterComboBoxes(); + } + + private void AddSlot() + { + _addSlotAction?.Invoke(); + } + + private void SaveSlots() + { + _saveAction?.Invoke(); + } + + private List GetSelectedSlots() + { + if (_mainView == null || _mainView._batchPanel == null) + throw new Exception("Meter batch grid is not available."); + + var slots = _mainView._batchPanel.GetSelectedGridData(); + + if (slots.Count == 0) + throw new Exception("No selected slots in grid."); + + return slots; + } + + private void RefreshGrid(int? removedSlot = null) + { + if (removedSlot.HasValue) + { + _mainView?._gciApi.SetSlotSelected(removedSlot.Value, false); + _mainView?._batchPanel?.RemoveSlotRow(removedSlot.Value); + } + + if (_bridge?.gciExternalInterface != null) + _bridge.gciExternalInterface.RaiseMeterBatchStatusChanged(); + } + + + private void btnCancel_Click(object sender, EventArgs e) + { + _cts?.Cancel(); + Log("Cancel requested."); + } + + private async void ExecuteAsync(Func action) + { + try + { + SetBusy(true); + + _cts = new CancellationTokenSource(); + + await action(_cts.Token); + } + catch (OperationCanceledException) + { + Log("Operation canceled."); + } + catch (Exception ex) + { + Log("ERROR: " + ex); + + MessageBox.Show( + ex.Message, + "GciBridge API call failed", + MessageBoxButtons.OK, + MessageBoxIcon.Error); + } + finally + { + _cts?.Dispose(); + _cts = null; + + SetBusy(false); + } + } + + private void SetBusy(bool busy) + { + Cursor = busy ? Cursors.WaitCursor : Cursors.Default; + + preparationActionButton.Enabled = !busy; + btnUpdateSlot.Enabled = !busy; + detectActionButton.Enabled = !busy; + btnCleanAllSlots.Enabled = !busy; + btnGetPcbId.Enabled = !busy; + btnConnect.Enabled = !busy; + btnDisconnect.Enabled = !busy; + readRegisterButton.Enabled = !busy; + writeRegisterButton.Enabled = !busy; + readRegisterNameComboBox.Enabled = !busy; + writeRegisterNameComboBox.Enabled = !busy; + writeRegisterValueTextBox.Enabled = !busy; + btnLogin.Enabled = !busy; + btnCleanSlot.Enabled = !busy; + + btnCancel.Enabled = busy; + } + + private void LogResult(string methodName, object result) + { + Log(methodName + " result:"); + Log(result == null ? "" : result.ToString()); + } + + private void Log(string message) + { + txtLog.AppendText( + DateTime.Now.ToString("HH:mm:ss.fff") + + " " + + message + + Environment.NewLine); + } + + private void LoadRegisterComboBoxes() + { + var registers = _bridge.GetAllRegisterNames(); + + readRegisterNameComboBox.Items.Clear(); + writeRegisterNameComboBox.Items.Clear(); + + readRegisterNameComboBox.Items.AddRange(registers.ToArray()); + writeRegisterNameComboBox.Items.AddRange(registers.ToArray()); + } + + private void grpSlots_Enter(object sender, EventArgs e) + { + + } + + private void preparationActionButton_Click( + object sender, + EventArgs e) + { + ExecuteAsync(async token => + { + var selectedSlots = + _mainView._batchPanel.GetSelectedGridData(); + + if (!selectedSlots.Any()) + { + Log("No selected slots."); + return; + } + + var pp = CreatePreparationProgress(); + + bool success = await _bridge.Preadjustment_PreparationAsync( + pp, + token); + + Log( + success + ? "Preparation completed." + : "Preparation failed."); + }); + } + + private void detectActionButton_Click( + object sender, + EventArgs e) + { + ExecuteAsync(async token => + { + var selectedSlots = + _mainView._batchPanel.GetSelectedGridData(); + + if (!selectedSlots.Any()) + { + Log("Detect: no selected slots."); + return; + } + + _mainView._laatzenApi._settings = CreatePreAdjustmentSettings(selectedSlots); + + _mainView._laatzenApi._meterControls = CreateMeterControls(selectedSlots); + + bool success = await _bridge.Preadjustment_DetectAsync( + token); + + Log( + success + ? "Detect completed." + : "Detect failed."); + + RefreshGrid(); + }); + } + + + private ProcessProgress CreatePreparationProgress() + { + return new ProcessProgress + { + Setting = new PreAdjustmentSettingsContainer + { + + TempOnly = false, + Culture = + Thread.CurrentThread.CurrentCulture + }, + + IsAutomaticMode = true + }; + } + + private List CreateMeterControls(IEnumerable slots) + { + var controls = + new List(); + + foreach (var slot in slots) + { + var ctl = new MeterStateControl(slot.Slot); + + ctl.SetChecked(true); + ctl.IsEnabled = true; + + controls.Add(ctl); + } + + return controls; + } + + private PreAdjustmentSettingsContainer CreatePreAdjustmentSettings(IEnumerable slots) + { + var settings = + new PreAdjustmentSettingsContainer(); + + settings.Meters = + slots.Select(s => s.Slot).ToList(); + + settings.TempMeters = + new List(); + + settings.NumberOfPaths = 2; + settings.TempOnly = false; + settings.Culture = + Thread.CurrentThread.CurrentCulture; + + return settings; + } + + private void writeRegisterButton_Click(object sender, EventArgs e) + { + /*ExecuteAsync(async token => + { + string registerName = Convert.ToString(writeRegisterNameComboBox.Text).Trim(); + string valueText = writeRegisterValueTextBox.Text.Trim(); + + if (string.IsNullOrWhiteSpace(registerName)) + throw new Exception("Write register name is empty."); + + if (string.IsNullOrWhiteSpace(valueText)) + throw new Exception("Write register value is empty."); + + object value; + + if (registerName == "GENESISFLOW_LedMode") + { + value = byte.Parse(valueText); + } + else + { + value = valueText; + } + + var tasks = GetSelectedSlots() + .Select(async slot => + { + //var result = await _bridge.WriteRegisterAsync(slot.Slot, registerName, value, false, false, token); + //var result = await _bridge.WriteRegisterWithRetryAsync(slot.Slot, registerName, value, false, false, token); + + var result = Xylem.Common.Ui.CordonelPreadjustmentUi. Processes.WriteRegisterSafe(meter, "Calibration factor1", Register.Genesisflow.CalFactor1, setting.CalFactor1); + Processes + + return new + { + Slot = slot.Slot, + Result = result + }; + }) + .ToList(); + + var results = await Task.WhenAll(tasks); + + foreach (var item in results.OrderBy(x => x.Slot)) + { + LogResult( + $"WriteRegisterAsync slot {item.Slot}, register {registerName}, value {value}", + item.Result); + } + + RefreshGrid(); + });*/ + } + } +} \ No newline at end of file diff --git a/TBF/Rig/BridgeComponents/GciBridge/UI/StaraTuraAPI_GciBridge/GenesisCordonelInterfaceView.resx b/TBF/Rig/BridgeComponents/GciBridge/UI/StaraTuraAPI_GciBridge/PreadjustmentActionsView.resx similarity index 100% rename from TBF/Rig/BridgeComponents/GciBridge/UI/StaraTuraAPI_GciBridge/GenesisCordonelInterfaceView.resx rename to TBF/Rig/BridgeComponents/GciBridge/UI/StaraTuraAPI_GciBridge/PreadjustmentActionsView.resx diff --git a/TBF/Rig/BridgeComponents/GciBridge/UI/StaraTuraAPI_GciBridge/GenesisCordonelInterfaceView.Designer.cs b/TBF/Rig/BridgeComponents/GciBridge/UI/StaraTuraAPI_GciBridge/SlotsComPortsRegistersActionsView.Designer.cs similarity index 99% rename from TBF/Rig/BridgeComponents/GciBridge/UI/StaraTuraAPI_GciBridge/GenesisCordonelInterfaceView.Designer.cs rename to TBF/Rig/BridgeComponents/GciBridge/UI/StaraTuraAPI_GciBridge/SlotsComPortsRegistersActionsView.Designer.cs index 6ab933468..32a7ee738 100644 --- a/TBF/Rig/BridgeComponents/GciBridge/UI/StaraTuraAPI_GciBridge/GenesisCordonelInterfaceView.Designer.cs +++ b/TBF/Rig/BridgeComponents/GciBridge/UI/StaraTuraAPI_GciBridge/SlotsComPortsRegistersActionsView.Designer.cs @@ -1,6 +1,6 @@ namespace TBF.Rig.BridgeComponents.GciBridge.UI.StaraTuraAPI_GciBridge { - partial class GenesisCordonelInterfaceView + partial class SlotsComPortsRegistersActionsView { private System.ComponentModel.IContainer components = null; diff --git a/TBF/Rig/BridgeComponents/GciBridge/UI/StaraTuraAPI_GciBridge/GenesisCordonelInterfaceView.cs b/TBF/Rig/BridgeComponents/GciBridge/UI/StaraTuraAPI_GciBridge/SlotsComPortsRegistersActionsView.cs similarity index 99% rename from TBF/Rig/BridgeComponents/GciBridge/UI/StaraTuraAPI_GciBridge/GenesisCordonelInterfaceView.cs rename to TBF/Rig/BridgeComponents/GciBridge/UI/StaraTuraAPI_GciBridge/SlotsComPortsRegistersActionsView.cs index fe757db8c..eb9331d09 100644 --- a/TBF/Rig/BridgeComponents/GciBridge/UI/StaraTuraAPI_GciBridge/GenesisCordonelInterfaceView.cs +++ b/TBF/Rig/BridgeComponents/GciBridge/UI/StaraTuraAPI_GciBridge/SlotsComPortsRegistersActionsView.cs @@ -10,7 +10,7 @@ using GciPublicModels = GenesisCordonelInterface.API.PublicModels; namespace TBF.Rig.BridgeComponents.GciBridge.UI.StaraTuraAPI_GciBridge { - public partial class GenesisCordonelInterfaceView : UserControl + public partial class SlotsComPortsRegistersActionsView : UserControl { private readonly GciBridge _bridge; private readonly MainView _mainView; @@ -18,7 +18,7 @@ namespace TBF.Rig.BridgeComponents.GciBridge.UI.StaraTuraAPI_GciBridge private readonly Action _addSlotAction; private readonly Action _saveAction; - public GenesisCordonelInterfaceView( + public SlotsComPortsRegistersActionsView( MainView mainview, GciBridge bridge, Action addSlotAction, diff --git a/TBF/Rig/BridgeComponents/GciBridge/UI/StaraTuraAPI_GciBridge/UniDataStorageReaderInterfaceView.resx b/TBF/Rig/BridgeComponents/GciBridge/UI/StaraTuraAPI_GciBridge/SlotsComPortsRegistersActionsView.resx similarity index 100% rename from TBF/Rig/BridgeComponents/GciBridge/UI/StaraTuraAPI_GciBridge/UniDataStorageReaderInterfaceView.resx rename to TBF/Rig/BridgeComponents/GciBridge/UI/StaraTuraAPI_GciBridge/SlotsComPortsRegistersActionsView.resx diff --git a/TBF/Rig/BridgeComponents/GciBridge/UI/StaraTuraAPI_GciBridge/UniDataStorageReaderInterfaceView.Designer.cs b/TBF/Rig/BridgeComponents/GciBridge/UI/StaraTuraAPI_GciBridge/UniDataSorageActionsView.Designer.cs similarity index 96% rename from TBF/Rig/BridgeComponents/GciBridge/UI/StaraTuraAPI_GciBridge/UniDataStorageReaderInterfaceView.Designer.cs rename to TBF/Rig/BridgeComponents/GciBridge/UI/StaraTuraAPI_GciBridge/UniDataSorageActionsView.Designer.cs index 86b0fdfc8..c893830fd 100644 --- a/TBF/Rig/BridgeComponents/GciBridge/UI/StaraTuraAPI_GciBridge/UniDataStorageReaderInterfaceView.Designer.cs +++ b/TBF/Rig/BridgeComponents/GciBridge/UI/StaraTuraAPI_GciBridge/UniDataSorageActionsView.Designer.cs @@ -1,12 +1,10 @@ namespace TBF.Rig.BridgeComponents.GciBridge.UI.StaraTuraAPI_GciBridge { - partial class UniDataStorageReaderInterfaceView + partial class UniDataSorageActionsView { private System.ComponentModel.IContainer components = null; private System.Windows.Forms.GroupBox grpStorage; - private System.Windows.Forms.Label lblPcbId; - private System.Windows.Forms.TextBox txtPcbId; private System.Windows.Forms.Button btnGetPasswordByPcb; private System.Windows.Forms.Button btnCancel; @@ -23,11 +21,11 @@ private void InitializeComponent() { this.grpStorage = new System.Windows.Forms.GroupBox(); - this.lblPcbId = new System.Windows.Forms.Label(); - this.txtPcbId = new System.Windows.Forms.TextBox(); this.btnGetPasswordByPcb = new System.Windows.Forms.Button(); this.btnCancel = new System.Windows.Forms.Button(); this.txtLog = new System.Windows.Forms.TextBox(); + this.lblPcbId = new System.Windows.Forms.Label(); + this.txtPcbId = new System.Windows.Forms.TextBox(); this.grpStorage.SuspendLayout(); this.SuspendLayout(); // @@ -38,27 +36,11 @@ this.grpStorage.Controls.Add(this.btnGetPasswordByPcb); this.grpStorage.Location = new System.Drawing.Point(10, 37); this.grpStorage.Name = "grpStorage"; - this.grpStorage.Size = new System.Drawing.Size(200, 120); + this.grpStorage.Size = new System.Drawing.Size(200, 261); this.grpStorage.TabIndex = 0; this.grpStorage.TabStop = false; this.grpStorage.Text = "UniDataStorageReader for GCI"; // - // lblPcbId - // - this.lblPcbId.AutoSize = true; - this.lblPcbId.Location = new System.Drawing.Point(10, 25); - this.lblPcbId.Name = "lblPcbId"; - this.lblPcbId.Size = new System.Drawing.Size(45, 13); - this.lblPcbId.TabIndex = 0; - this.lblPcbId.Text = "PCB ID:"; - // - // txtPcbId - // - this.txtPcbId.Location = new System.Drawing.Point(65, 22); - this.txtPcbId.Name = "txtPcbId"; - this.txtPcbId.Size = new System.Drawing.Size(120, 20); - this.txtPcbId.TabIndex = 1; - // // btnGetPasswordByPcb // this.btnGetPasswordByPcb.Location = new System.Drawing.Point(10, 55); @@ -91,12 +73,28 @@ this.txtLog.TabIndex = 4; this.txtLog.WordWrap = false; // - // UniDataStorageReaderInterfaceView + // lblPcbId + // + this.lblPcbId.AutoSize = true; + this.lblPcbId.Location = new System.Drawing.Point(10, 25); + this.lblPcbId.Name = "lblPcbId"; + this.lblPcbId.Size = new System.Drawing.Size(45, 13); + this.lblPcbId.TabIndex = 0; + this.lblPcbId.Text = "PCB ID:"; + // + // txtPcbId + // + this.txtPcbId.Location = new System.Drawing.Point(65, 22); + this.txtPcbId.Name = "txtPcbId"; + this.txtPcbId.Size = new System.Drawing.Size(120, 20); + this.txtPcbId.TabIndex = 1; + // + // UniDataSorageActionsView // this.Controls.Add(this.grpStorage); this.Controls.Add(this.btnCancel); this.Controls.Add(this.txtLog); - this.Name = "UniDataStorageReaderInterfaceView"; + this.Name = "UniDataSorageActionsView"; this.Size = new System.Drawing.Size(740, 370); this.grpStorage.ResumeLayout(false); this.grpStorage.PerformLayout(); @@ -104,5 +102,8 @@ this.PerformLayout(); } + + private System.Windows.Forms.Label lblPcbId; + private System.Windows.Forms.TextBox txtPcbId; } } \ No newline at end of file diff --git a/TBF/Rig/BridgeComponents/GciBridge/UI/StaraTuraAPI_GciBridge/UniDataStorageReaderInterfaceView.cs b/TBF/Rig/BridgeComponents/GciBridge/UI/StaraTuraAPI_GciBridge/UniDataSorageActionsView.cs similarity index 94% rename from TBF/Rig/BridgeComponents/GciBridge/UI/StaraTuraAPI_GciBridge/UniDataStorageReaderInterfaceView.cs rename to TBF/Rig/BridgeComponents/GciBridge/UI/StaraTuraAPI_GciBridge/UniDataSorageActionsView.cs index c667f6194..da90e5da3 100644 --- a/TBF/Rig/BridgeComponents/GciBridge/UI/StaraTuraAPI_GciBridge/UniDataStorageReaderInterfaceView.cs +++ b/TBF/Rig/BridgeComponents/GciBridge/UI/StaraTuraAPI_GciBridge/UniDataSorageActionsView.cs @@ -5,13 +5,13 @@ using System.Windows.Forms; namespace TBF.Rig.BridgeComponents.GciBridge.UI.StaraTuraAPI_GciBridge { - public partial class UniDataStorageReaderInterfaceView : UserControl + public partial class UniDataSorageActionsView : UserControl { private readonly MainView _mainView; private readonly GciBridge _bridge; private CancellationTokenSource _cts; - public UniDataStorageReaderInterfaceView(MainView mainView, GciBridge bridge) + public UniDataSorageActionsView(MainView mainView, GciBridge bridge) { _mainView = mainView ?? throw new ArgumentNullException(nameof(mainView)); _bridge = bridge ?? throw new ArgumentNullException(nameof(bridge)); diff --git a/TBF/Rig/BridgeComponents/GciBridge/UI/StaraTuraAPI_GciBridge/UniDataSorageActionsView.resx b/TBF/Rig/BridgeComponents/GciBridge/UI/StaraTuraAPI_GciBridge/UniDataSorageActionsView.resx new file mode 100644 index 000000000..1af7de150 --- /dev/null +++ b/TBF/Rig/BridgeComponents/GciBridge/UI/StaraTuraAPI_GciBridge/UniDataSorageActionsView.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/TBF/TBF.csproj b/TBF/TBF.csproj index 223d045ab..2eaeb68a6 100644 --- a/TBF/TBF.csproj +++ b/TBF/TBF.csproj @@ -253,17 +253,23 @@ MainView.cs - + UserControl - - UniDataStorageReaderInterfaceView.cs + + PreadjustmentActionsView.cs - + UserControl - - CombinedInterfaceView.cs + + UniDataSorageActionsView.cs + + + UserControl + + + CombinedActionsView.cs UserControl @@ -271,11 +277,11 @@ ConfigurationView.cs - + UserControl - - GenesisCordonelInterfaceView.cs + + SlotsComPortsRegistersActionsView.cs @@ -3310,17 +3316,20 @@ MainView.cs - - CombinedInterfaceView.cs + + CombinedActionsView.cs ConfigurationView.cs - - UniDataStorageReaderInterfaceView.cs + + PreadjustmentActionsView.cs - - GenesisCordonelInterfaceView.cs + + UniDataSorageActionsView.cs + + + SlotsComPortsRegistersActionsView.cs PumpCfgCtrl.cs @@ -4437,6 +4446,14 @@ {439D0878-C76E-452B-B17D-209A89E91D36} Dirichlet.Numerics + + {d0c8d887-ed52-40ab-a069-90bce0e801e2} + CordonelPreadjustmentUi + + + {6d2777bb-7a88-466d-a49b-3266f9bf0160} + ProductionOrderCore + {8B10D15A-39DE-4B56-8DD1-710C1EB3A697} GemCard From bc72130d0956d41c1eb705655350c7e48932d593 Mon Sep 17 00:00:00 2001 From: Marek Frniak Date: Thu, 21 May 2026 08:16:02 +0200 Subject: [PATCH 3/4] Develop - GciBridge -> GCI -> PreadjustmentUI functions 2 --- .../API/InterfaceGCIToLaatzen.cs | 167 ++++++++++ .../API/InterfaceOutsideToGCI.cs | 34 +- .../Core/Threading/RetryWorker/RetryWorker.cs | 85 ++++- .../BridgeComponents/GciBridge/GciBridge.cs | 176 +++++++++++ .../UI/Debug/MeterBatchConfigPanel.cs | 11 +- .../GciBridge/UI/Grid/MeterGridManager.cs | 3 +- .../PreadjustmentActionsView.Designer.cs | 293 ++++++++---------- .../PreadjustmentActionsView.cs | 90 ++++-- ...tsComPortsRegistersActionsView.Designer.cs | 27 +- .../SlotsComPortsRegistersActionsView.cs | 182 +++++++++-- TBF/TBF.csproj | 4 + 11 files changed, 851 insertions(+), 221 deletions(-) diff --git a/GenesisCordonelInterface/API/InterfaceGCIToLaatzen.cs b/GenesisCordonelInterface/API/InterfaceGCIToLaatzen.cs index b451d1ad7..510c87cf0 100644 --- a/GenesisCordonelInterface/API/InterfaceGCIToLaatzen.cs +++ b/GenesisCordonelInterface/API/InterfaceGCIToLaatzen.cs @@ -243,6 +243,16 @@ namespace GenesisCordonelInterface.API return string.IsNullOrWhiteSpace(port) ? "" : port; } + public ConcurrentDictionary GetRegistersDicForSlot(int slot) + { + var meter = GetMeterThreadSafe(slot); + + if (meter == null) + throw new Exception($"Slot {slot} not initialized."); + + return meter.GetRegistersDic(); + } + #endregion #region ================================== INIT/UPDATE ================================== @@ -1748,6 +1758,163 @@ namespace GenesisCordonelInterface.API #endregion + #region ================================== PreAdjustmentUI AMPLITUDE TEST process ================================== + + /// + /// Execute standalone amplitude test process. + /// + public Task Preadjustment_AmplitudeTestAsync( + ProcessProgress pp, + CancellationToken token = default) + { + if (pp.Setting.TempOnly) + return Task.FromResult(true); + + IProcess process; + + if (pp.Setting.NumberOfPaths == 1) + { + process = + new SPAmplitudeTestProcess( + "Amplitude Test Single", + PreAdjustmentControl.StatusPanelItems.Amplitude, + PreAdjustmentControl.PredefinedMessages.WaitUntilAmplitudeTestFinished(pp.Setting.Culture), + PreAdjustmentControl.PredefinedMessages.AmplitudeFailed(pp.Setting.Culture), + 4 * 60); + } + else + { + process = + new AmplitudeTestProcess( + "Amplitude Test", + PreAdjustmentControl.StatusPanelItems.Amplitude, + PreAdjustmentControl.PredefinedMessages.WaitUntilAmplitudeTestFinished(pp.Setting.Culture), + PreAdjustmentControl.PredefinedMessages.AmplitudeFailed(pp.Setting.Culture), + 4 * 60); + } + + return ExecuteProcessAsync( + process, + pp, + token); + } + + #endregion + + #region ================================== PreAdjustmentUI TEMPERATURE CALIBRATION process ================================== + + public Task Preadjustment_TemperatureCalibrationAsync( + ProcessProgress pp, + CancellationToken token = default) + { + IProcess process; + + if (pp.Setting.NumberOfPaths == 1) + { + process = + new SPTemperatureCalibrationProcess( + "Temperature Calibration Single", + PreAdjustmentControl.StatusPanelItems.TempCal, + PreAdjustmentControl.PredefinedMessages.WaitUntilTemperatureCalibrationFinished(pp.Setting.Culture), + PreAdjustmentControl.PredefinedMessages.TempCalFailed(pp.Setting.Culture), + 2 * 60); + } + else + { + process = + new TemperatureCalibrationProcess( + "Temperature Calibration", + PreAdjustmentControl.StatusPanelItems.TempCal, + PreAdjustmentControl.PredefinedMessages.WaitUntilTemperatureCalibrationFinished(pp.Setting.Culture), + PreAdjustmentControl.PredefinedMessages.TempCalFailed(pp.Setting.Culture), + 2 * 60); + } + + return ExecuteProcessAsync( + process, + pp, + token); + } + + #endregion + + #region ================================== PreAdjustmentUI OFFSET TEST process ================================== + + public Task Preadjustment_OffsetTestAsync( + ProcessProgress pp, + CancellationToken token = default) + { + if (pp.Setting.TempOnly) + return Task.FromResult(true); + + IProcess process; + + if (pp.Setting.NumberOfPaths == 1) + { + process = + new SPOffsetTestProcess( + "Offset Test Single", + PreAdjustmentControl.StatusPanelItems.Offset, + PreAdjustmentControl.PredefinedMessages.WaitUntilZeroflowOffsetTestFinished(pp.Setting.Culture), + PreAdjustmentControl.PredefinedMessages.ZeroflowOffsetTestFailed(pp.Setting.Culture), + 18 * 60); + } + else + { + process = + new OffsetTestProcess( + "Offset Test", + PreAdjustmentControl.StatusPanelItems.Offset, + PreAdjustmentControl.PredefinedMessages.WaitUntilZeroflowOffsetTestFinished(pp.Setting.Culture), + PreAdjustmentControl.PredefinedMessages.ZeroflowOffsetTestFailed(pp.Setting.Culture), + 18 * 60); + } + + return ExecuteProcessAsync( + process, + pp, + token); + } + + #endregion + + #region ================================== PreAdjustmentUI COMPLETION process ================================== + + public Task Preadjustment_CompletionAsync( + ProcessProgress pp, + CancellationToken token = default) + { + IProcess process; + + if (pp.Setting.NumberOfPaths == 1) + { + process = + new SPCompletionProcess( + "Completion Single", + PreAdjustmentControl.StatusPanelItems.Completion, + PreAdjustmentControl.PredefinedMessages.WaitUntilCompletionFinished(pp.Setting.Culture), + PreAdjustmentControl.PredefinedMessages.CompletionFailed(pp.Setting.Culture), + 1 * 60); + } + else + { + process = + new CompletionProcess( + "Completion", + PreAdjustmentControl.StatusPanelItems.Completion, + PreAdjustmentControl.PredefinedMessages.WaitUntilCompletionFinished(pp.Setting.Culture), + PreAdjustmentControl.PredefinedMessages.CompletionFailed(pp.Setting.Culture), + 1 * 60); + } + + return ExecuteProcessAsync( + process, + pp, + token); + } + + #endregion + #region ================================== PreAdjustmentUI process threading ================================== public async Task ExecuteProcessAsync( diff --git a/GenesisCordonelInterface/API/InterfaceOutsideToGCI.cs b/GenesisCordonelInterface/API/InterfaceOutsideToGCI.cs index 40b6bd4ab..7082ea5ad 100644 --- a/GenesisCordonelInterface/API/InterfaceOutsideToGCI.cs +++ b/GenesisCordonelInterface/API/InterfaceOutsideToGCI.cs @@ -466,11 +466,37 @@ namespace GenesisCordonelInterface.API ProcessProgress pp, CancellationToken token = default) { - return _innerMeterAPI.Preadjustment_PreparationAsync( - pp, - token); + return _innerMeterAPI.Preadjustment_PreparationAsync(pp, token); } - + public Task Preadjustment_AmplitudeTestAsync( + ProcessProgress pp, + CancellationToken token = default) + { + return _innerMeterAPI.Preadjustment_AmplitudeTestAsync(pp, token); + } + + public Task Preadjustment_TemperatureCalibrationAsync( + ProcessProgress pp, + CancellationToken token = default) + { + return _innerMeterAPI.Preadjustment_TemperatureCalibrationAsync(pp, token); + } + + public Task Preadjustment_OffsetTestAsync( + ProcessProgress pp, + CancellationToken token = default) + { + return _innerMeterAPI.Preadjustment_OffsetTestAsync(pp, token); + } + + public Task Preadjustment_CompletionAsync( + ProcessProgress pp, + CancellationToken token = default) + { + return _innerMeterAPI.Preadjustment_CompletionAsync(pp, token); + } + + } } \ No newline at end of file diff --git a/GenesisCordonelInterface/Core/Threading/RetryWorker/RetryWorker.cs b/GenesisCordonelInterface/Core/Threading/RetryWorker/RetryWorker.cs index 003395fbf..73f98e42f 100644 --- a/GenesisCordonelInterface/Core/Threading/RetryWorker/RetryWorker.cs +++ b/GenesisCordonelInterface/Core/Threading/RetryWorker/RetryWorker.cs @@ -25,6 +25,15 @@ namespace GenesisCordonelInterface.Core.Threading public static class RetryWorker { + /// + /// Executes an asynchronous operation with retry and timeout protection. + /// + /// Important: + /// The timeout here protects the caller from waiting forever, but it does not forcibly abort + /// the underlying hardware operation. Because hardware/COM calls may continue running after + /// the timeout signal, this method waits for the original action to finish before starting + /// the next retry. This prevents overlapping COM requests on the same device. + /// public static async Task> RunWithRetryAsync( Func> action, Func isSuccess, @@ -41,21 +50,53 @@ namespace GenesisCordonelInterface.Core.Threading for (int attempt = 1; attempt <= maxAttempts; attempt++) { - var actionTask = action(); - var timeoutTask = Task.Delay(timeoutMs); + Task actionTask = null; - var completedTask = await Task.WhenAny(actionTask, timeoutTask); - - if (completedTask == timeoutTask) + try { - timedOut = true; - log?.Invoke($"{operationName} timeout attempt {attempt}/{maxAttempts}"); - } - else - { - lastResult = await actionTask; + log?.Invoke($"{operationName} started. Attempt {attempt}/{maxAttempts}"); - if (isSuccess(lastResult)) + // Start real operation, for example Connect/GetPcbId/Login. + actionTask = action(); + + // Start independent timeout timer. + var timeoutTask = Task.Delay(timeoutMs); + + // Wait until either operation completes or timeout expires. + var completedTask = await Task.WhenAny(actionTask, timeoutTask) + .ConfigureAwait(false); + + if (completedTask == timeoutTask) + { + timedOut = true; + + log?.Invoke( + $"{operationName} timed out. Attempt {attempt}/{maxAttempts}. " + + "Waiting for the running operation to finish before retry."); + + // Critical part: + // Do NOT immediately start another retry. + // The hardware operation may still be active in ApiWorker. + // Starting another attempt immediately could corrupt communication. + try + { + lastResult = await actionTask.ConfigureAwait(false); + } + catch (Exception ex) + { + log?.Invoke( + $"{operationName} finished after timeout with exception: " + + $"{ex.GetType().Name}: {ex.Message}"); + } + } + else + { + // Operation completed before timeout. + lastResult = await actionTask.ConfigureAwait(false); + } + + // Decide whether the returned result means success. + if (lastResult != null && isSuccess(lastResult)) { return new RetryResult { @@ -63,15 +104,29 @@ namespace GenesisCordonelInterface.Core.Threading Success = true, Attempts = attempt, Duration = DateTime.Now - started, - TimedOut = false + TimedOut = timedOut }; } - logResult?.Invoke($"{operationName} failed attempt {attempt}/{maxAttempts}", lastResult); + logResult?.Invoke( + $"{operationName} failed. Attempt {attempt}/{maxAttempts}", + lastResult); + } + catch (Exception ex) + { + // Covers exceptions thrown before timeout handling or by action startup. + log?.Invoke( + $"{operationName} exception on attempt {attempt}/{maxAttempts}: " + + $"{ex.GetType().Name}: {ex.Message}"); } + // Delay before next retry, except after the final attempt. if (attempt < maxAttempts) - await Task.Delay(delayMs); + { + log?.Invoke($"{operationName} waiting {delayMs} ms before retry."); + + await Task.Delay(delayMs).ConfigureAwait(false); + } } return new RetryResult diff --git a/TBF/Rig/BridgeComponents/GciBridge/GciBridge.cs b/TBF/Rig/BridgeComponents/GciBridge/GciBridge.cs index 48403914b..cb7bd1b48 100644 --- a/TBF/Rig/BridgeComponents/GciBridge/GciBridge.cs +++ b/TBF/Rig/BridgeComponents/GciBridge/GciBridge.cs @@ -1505,6 +1505,182 @@ namespace TBF.Rig.BridgeComponents.GciBridge #endregion + #region ================================== PreAdjustment AMPLITUDE TEST bridge ================================== + + public async Task Preadjustment_AmplitudeTestAsync( + ProcessProgress pp, + CancellationToken token = default) + { + const string operation = nameof(Preadjustment_AmplitudeTestAsync); + + try + { + EnsureExternalInterface(); + + if (pp == null) + throw new ArgumentNullException(nameof(pp)); + + log.InfoFormat("{0}: {1} Start.", Name, operation); + + bool result = + await gciExternalInterface + .Preadjustment_AmplitudeTestAsync( + pp, + token) + .ConfigureAwait(false); + + log.InfoFormat( + "{0}: {1} Finish. Success={2}", + Name, + operation, + result); + + return result; + } + catch (Exception ex) + { + log.Error( + string.Format("{0}: {1} failed.", Name, operation), + ex); + + return false; + } + } + + #endregion + + #region ================================== PreAdjustment TEMPERATURE CALIBRATION bridge ================================== + + public async Task Preadjustment_TemperatureCalibrationAsync( + ProcessProgress pp, + CancellationToken token = default) + { + const string operation = nameof(Preadjustment_TemperatureCalibrationAsync); + + try + { + EnsureExternalInterface(); + + if (pp == null) + throw new ArgumentNullException(nameof(pp)); + + log.InfoFormat("{0}: {1} Start.", Name, operation); + + bool result = + await gciExternalInterface + .Preadjustment_TemperatureCalibrationAsync( + pp, + token) + .ConfigureAwait(false); + + log.InfoFormat( + "{0}: {1} Finish. Success={2}", + Name, + operation, + result); + + return result; + } + catch (Exception ex) + { + log.Error( + string.Format("{0}: {1} failed.", Name, operation), + ex); + + return false; + } + } + + #endregion + + #region ================================== PreAdjustment OFFSET TEST bridge ================================== + + public async Task Preadjustment_OffsetTestAsync( + ProcessProgress pp, + CancellationToken token = default) + { + const string operation = nameof(Preadjustment_OffsetTestAsync); + + try + { + EnsureExternalInterface(); + + if (pp == null) + throw new ArgumentNullException(nameof(pp)); + + log.InfoFormat("{0}: {1} Start.", Name, operation); + + bool result = + await gciExternalInterface + .Preadjustment_OffsetTestAsync( + pp, + token) + .ConfigureAwait(false); + + log.InfoFormat( + "{0}: {1} Finish. Success={2}", + Name, + operation, + result); + + return result; + } + catch (Exception ex) + { + log.Error( + string.Format("{0}: {1} failed.", Name, operation), + ex); + + return false; + } + } + + #endregion + + #region ================================== PreAdjustment COMPLETION bridge ================================== + + public async Task Preadjustment_CompletionAsync( + ProcessProgress pp, + CancellationToken token = default) + { + const string operation = nameof(Preadjustment_CompletionAsync); + + try + { + EnsureExternalInterface(); + + if (pp == null) + throw new ArgumentNullException(nameof(pp)); + + log.InfoFormat("{0}: {1} Start.", Name, operation); + + bool result = + await gciExternalInterface + .Preadjustment_CompletionAsync( + pp, + token) + .ConfigureAwait(false); + + log.InfoFormat( + "{0}: {1} Finish. Success={2}", + Name, + operation, + result); + + return result; + } + catch (Exception ex) + { + log.Error( + string.Format("{0}: {1} failed.", Name, operation), + ex); + + return false; + } + } + + #endregion + #region ======================================= Helpers ======================================= private UDSRPublicModels.DataQuery CreatePasswordQuery(string pcbId) { diff --git a/TBF/Rig/BridgeComponents/GciBridge/UI/Debug/MeterBatchConfigPanel.cs b/TBF/Rig/BridgeComponents/GciBridge/UI/Debug/MeterBatchConfigPanel.cs index 34e236265..9d37054e2 100644 --- a/TBF/Rig/BridgeComponents/GciBridge/UI/Debug/MeterBatchConfigPanel.cs +++ b/TBF/Rig/BridgeComponents/GciBridge/UI/Debug/MeterBatchConfigPanel.cs @@ -15,6 +15,7 @@ namespace TBF.Rig.BridgeComponents.GciBridge.UI.Debug private MainForm _mainform; private MainView _mainView; public Grid.MeterGridManager _gridManager; + public event Action SelectedSlotsChanged; private bool isRefreshing; private List comPorts = new List(); @@ -267,8 +268,16 @@ namespace TBF.Rig.BridgeComponents.GciBridge.UI.Debug if (columnName == "Selected") { - bool selected = Convert.ToBoolean(grid.Rows[e.RowIndex].Cells["Selected"].Value); + bool selected = + Convert.ToBoolean( + grid.Rows[e.RowIndex] + .Cells["Selected"] + .Value); + _api.SetSlotSelected(slot, selected); + + SelectedSlotsChanged?.Invoke(); + return; } diff --git a/TBF/Rig/BridgeComponents/GciBridge/UI/Grid/MeterGridManager.cs b/TBF/Rig/BridgeComponents/GciBridge/UI/Grid/MeterGridManager.cs index f4299069c..451ab33fb 100644 --- a/TBF/Rig/BridgeComponents/GciBridge/UI/Grid/MeterGridManager.cs +++ b/TBF/Rig/BridgeComponents/GciBridge/UI/Grid/MeterGridManager.cs @@ -1,4 +1,5 @@ -using System; +using Common; +using System; using System.Collections.Generic; using System.Linq; using System.Reflection; diff --git a/TBF/Rig/BridgeComponents/GciBridge/UI/StaraTuraAPI_GciBridge/PreadjustmentActionsView.Designer.cs b/TBF/Rig/BridgeComponents/GciBridge/UI/StaraTuraAPI_GciBridge/PreadjustmentActionsView.Designer.cs index b08992b0c..2ddcfac27 100644 --- a/TBF/Rig/BridgeComponents/GciBridge/UI/StaraTuraAPI_GciBridge/PreadjustmentActionsView.Designer.cs +++ b/TBF/Rig/BridgeComponents/GciBridge/UI/StaraTuraAPI_GciBridge/PreadjustmentActionsView.Designer.cs @@ -7,9 +7,8 @@ private System.Windows.Forms.GroupBox grpSlots; private System.Windows.Forms.Button preparationActionButton; - private System.Windows.Forms.Button btnUpdateSlot; private System.Windows.Forms.Button detectActionButton; - private System.Windows.Forms.Button btnCleanAllSlots; + private System.Windows.Forms.Button temperatureCalibrationActionButton; private System.Windows.Forms.Button btnCancel; private System.Windows.Forms.TextBox txtLog; @@ -25,47 +24,41 @@ private void InitializeComponent() { this.grpSlots = new System.Windows.Forms.GroupBox(); - this.writeRegisterNameComboBox = new System.Windows.Forms.ComboBox(); - this.readRegisterNameComboBox = new System.Windows.Forms.ComboBox(); - this.label4 = new System.Windows.Forms.Label(); - this.writeRegisterValueTextBox = new System.Windows.Forms.TextBox(); - this.label3 = new System.Windows.Forms.Label(); - this.label2 = new System.Windows.Forms.Label(); - this.writeRegisterButton = new System.Windows.Forms.Button(); - this.readRegisterButton = new System.Windows.Forms.Button(); - this.btnConnect = new System.Windows.Forms.Button(); - this.btnDisconnect = new System.Windows.Forms.Button(); - this.btnLogin = new System.Windows.Forms.Button(); - this.btnGetPcbId = new System.Windows.Forms.Button(); + this.completionActionButton = new System.Windows.Forms.Button(); + this.offsetTestActionButton = new System.Windows.Forms.Button(); this.preparationActionButton = new System.Windows.Forms.Button(); - this.btnUpdateSlot = new System.Windows.Forms.Button(); this.detectActionButton = new System.Windows.Forms.Button(); - this.btnCleanAllSlots = new System.Windows.Forms.Button(); - this.btnCleanSlot = new System.Windows.Forms.Button(); + this.temperatureCalibrationActionButton = new System.Windows.Forms.Button(); + this.amplitudeTestActionButton = new System.Windows.Forms.Button(); this.btnCancel = new System.Windows.Forms.Button(); this.txtLog = new System.Windows.Forms.TextBox(); + this.button1 = new System.Windows.Forms.Button(); + this.label1 = new System.Windows.Forms.Label(); + this.label2 = new System.Windows.Forms.Label(); + this.label3 = new System.Windows.Forms.Label(); + this.label4 = new System.Windows.Forms.Label(); + this.label5 = new System.Windows.Forms.Label(); + this.label6 = new System.Windows.Forms.Label(); + this.label7 = new System.Windows.Forms.Label(); this.grpSlots.SuspendLayout(); this.SuspendLayout(); // // grpSlots // - this.grpSlots.Controls.Add(this.writeRegisterNameComboBox); - this.grpSlots.Controls.Add(this.readRegisterNameComboBox); + this.grpSlots.Controls.Add(this.label7); + this.grpSlots.Controls.Add(this.label6); + this.grpSlots.Controls.Add(this.label5); this.grpSlots.Controls.Add(this.label4); - this.grpSlots.Controls.Add(this.writeRegisterValueTextBox); this.grpSlots.Controls.Add(this.label3); this.grpSlots.Controls.Add(this.label2); - this.grpSlots.Controls.Add(this.writeRegisterButton); - this.grpSlots.Controls.Add(this.readRegisterButton); - this.grpSlots.Controls.Add(this.btnConnect); - this.grpSlots.Controls.Add(this.btnDisconnect); - this.grpSlots.Controls.Add(this.btnLogin); - this.grpSlots.Controls.Add(this.btnGetPcbId); + this.grpSlots.Controls.Add(this.label1); + this.grpSlots.Controls.Add(this.button1); + this.grpSlots.Controls.Add(this.completionActionButton); + this.grpSlots.Controls.Add(this.offsetTestActionButton); this.grpSlots.Controls.Add(this.preparationActionButton); - this.grpSlots.Controls.Add(this.btnUpdateSlot); this.grpSlots.Controls.Add(this.detectActionButton); - this.grpSlots.Controls.Add(this.btnCleanAllSlots); - this.grpSlots.Controls.Add(this.btnCleanSlot); + this.grpSlots.Controls.Add(this.temperatureCalibrationActionButton); + this.grpSlots.Controls.Add(this.amplitudeTestActionButton); this.grpSlots.Location = new System.Drawing.Point(10, 10); this.grpSlots.Name = "grpSlots"; this.grpSlots.Size = new System.Drawing.Size(689, 304); @@ -74,146 +67,56 @@ this.grpSlots.Text = "Slots by selection in the table"; this.grpSlots.Enter += new System.EventHandler(this.grpSlots_Enter); // - // writeRegisterNameComboBox + // completionActionButton // - this.writeRegisterNameComboBox.FormattingEnabled = true; - this.writeRegisterNameComboBox.Location = new System.Drawing.Point(300, 264); - this.writeRegisterNameComboBox.Name = "writeRegisterNameComboBox"; - this.writeRegisterNameComboBox.Size = new System.Drawing.Size(213, 21); - this.writeRegisterNameComboBox.TabIndex = 15; + this.completionActionButton.Location = new System.Drawing.Point(390, 249); + this.completionActionButton.Name = "completionActionButton"; + this.completionActionButton.Size = new System.Drawing.Size(150, 28); + this.completionActionButton.TabIndex = 3; + this.completionActionButton.Text = "Completition"; // - // readRegisterNameComboBox + // offsetTestActionButton // - this.readRegisterNameComboBox.FormattingEnabled = true; - this.readRegisterNameComboBox.Location = new System.Drawing.Point(300, 230); - this.readRegisterNameComboBox.Name = "readRegisterNameComboBox"; - this.readRegisterNameComboBox.Size = new System.Drawing.Size(213, 21); - this.readRegisterNameComboBox.TabIndex = 14; - // - // label4 - // - this.label4.AutoSize = true; - this.label4.Location = new System.Drawing.Point(224, 233); - this.label4.Name = "label4"; - this.label4.Size = new System.Drawing.Size(78, 13); - this.label4.TabIndex = 13; - this.label4.Text = "Register name:"; - // - // writeRegisterValueTextBox - // - this.writeRegisterValueTextBox.Location = new System.Drawing.Point(555, 264); - this.writeRegisterValueTextBox.Name = "writeRegisterValueTextBox"; - this.writeRegisterValueTextBox.Size = new System.Drawing.Size(117, 20); - this.writeRegisterValueTextBox.TabIndex = 12; - // - // label3 - // - this.label3.AutoSize = true; - this.label3.Location = new System.Drawing.Point(517, 267); - this.label3.Name = "label3"; - this.label3.Size = new System.Drawing.Size(36, 13); - this.label3.TabIndex = 10; - this.label3.Text = "value:"; - // - // label2 - // - this.label2.AutoSize = true; - this.label2.Location = new System.Drawing.Point(224, 267); - this.label2.Name = "label2"; - this.label2.Size = new System.Drawing.Size(78, 13); - this.label2.TabIndex = 9; - this.label2.Text = "Register name:"; - // - // writeRegisterButton - // - this.writeRegisterButton.Location = new System.Drawing.Point(15, 259); - this.writeRegisterButton.Name = "writeRegisterButton"; - this.writeRegisterButton.Size = new System.Drawing.Size(203, 28); - this.writeRegisterButton.TabIndex = 7; - this.writeRegisterButton.Text = "WriteRegister(slot, registerName, value)"; - this.writeRegisterButton.Click += new System.EventHandler(this.writeRegisterButton_Click); - // - // readRegisterButton - // - this.readRegisterButton.Location = new System.Drawing.Point(15, 225); - this.readRegisterButton.Name = "readRegisterButton"; - this.readRegisterButton.Size = new System.Drawing.Size(203, 28); - this.readRegisterButton.TabIndex = 6; - this.readRegisterButton.Text = "ReadRegister(slot, registerName)"; - // - // btnConnect - // - this.btnConnect.Location = new System.Drawing.Point(15, 158); - this.btnConnect.Name = "btnConnect"; - this.btnConnect.Size = new System.Drawing.Size(150, 28); - this.btnConnect.TabIndex = 3; - this.btnConnect.Text = "Connect(slot)"; - // - // btnDisconnect - // - this.btnDisconnect.Location = new System.Drawing.Point(15, 191); - this.btnDisconnect.Name = "btnDisconnect"; - this.btnDisconnect.Size = new System.Drawing.Size(150, 28); - this.btnDisconnect.TabIndex = 4; - this.btnDisconnect.Text = "Disconnect(slot)"; - // - // btnLogin - // - this.btnLogin.Location = new System.Drawing.Point(171, 158); - this.btnLogin.Name = "btnLogin"; - this.btnLogin.Size = new System.Drawing.Size(150, 28); - this.btnLogin.TabIndex = 17; - this.btnLogin.Text = "Login(slot)"; - // - // btnGetPcbId - // - this.btnGetPcbId.Location = new System.Drawing.Point(15, 125); - this.btnGetPcbId.Name = "btnGetPcbId"; - this.btnGetPcbId.Size = new System.Drawing.Size(150, 28); - this.btnGetPcbId.TabIndex = 5; - this.btnGetPcbId.Text = "GetPcb(slot)"; + this.offsetTestActionButton.Location = new System.Drawing.Point(334, 215); + this.offsetTestActionButton.Name = "offsetTestActionButton"; + this.offsetTestActionButton.Size = new System.Drawing.Size(150, 28); + this.offsetTestActionButton.TabIndex = 5; + this.offsetTestActionButton.Text = "Offset test"; // // preparationActionButton // - this.preparationActionButton.Location = new System.Drawing.Point(15, 25); + this.preparationActionButton.Location = new System.Drawing.Point(203, 113); this.preparationActionButton.Name = "preparationActionButton"; this.preparationActionButton.Size = new System.Drawing.Size(150, 28); this.preparationActionButton.TabIndex = 0; this.preparationActionButton.Text = "Preparation"; this.preparationActionButton.Click += new System.EventHandler(this.preparationActionButton_Click); // - // btnUpdateSlot - // - this.btnUpdateSlot.Location = new System.Drawing.Point(171, 25); - this.btnUpdateSlot.Name = "btnUpdateSlot"; - this.btnUpdateSlot.Size = new System.Drawing.Size(150, 28); - this.btnUpdateSlot.TabIndex = 16; - this.btnUpdateSlot.Text = "UpdateSlot(slot)"; - // // detectActionButton // - this.detectActionButton.Location = new System.Drawing.Point(15, 58); + this.detectActionButton.Location = new System.Drawing.Point(171, 79); this.detectActionButton.Name = "detectActionButton"; this.detectActionButton.Size = new System.Drawing.Size(150, 28); this.detectActionButton.TabIndex = 1; this.detectActionButton.Text = "Detect"; this.detectActionButton.Click += new System.EventHandler(this.detectActionButton_Click); // - // btnCleanAllSlots + // temperatureCalibrationActionButton // - this.btnCleanAllSlots.Location = new System.Drawing.Point(171, 92); - this.btnCleanAllSlots.Name = "btnCleanAllSlots"; - this.btnCleanAllSlots.Size = new System.Drawing.Size(150, 28); - this.btnCleanAllSlots.TabIndex = 2; - this.btnCleanAllSlots.Text = "CleanAllSlots()"; + this.temperatureCalibrationActionButton.Location = new System.Drawing.Point(285, 181); + this.temperatureCalibrationActionButton.Name = "temperatureCalibrationActionButton"; + this.temperatureCalibrationActionButton.Size = new System.Drawing.Size(150, 28); + this.temperatureCalibrationActionButton.TabIndex = 2; + this.temperatureCalibrationActionButton.Text = "Temperature calibration"; + this.temperatureCalibrationActionButton.Click += new System.EventHandler(this.amplitudeTestActionButton_Click); // - // btnCleanSlot + // amplitudeTestActionButton // - this.btnCleanSlot.Location = new System.Drawing.Point(15, 92); - this.btnCleanSlot.Name = "btnCleanSlot"; - this.btnCleanSlot.Size = new System.Drawing.Size(150, 28); - this.btnCleanSlot.TabIndex = 18; - this.btnCleanSlot.Text = "CleanSlot(slot)"; + this.amplitudeTestActionButton.Location = new System.Drawing.Point(246, 147); + this.amplitudeTestActionButton.Name = "amplitudeTestActionButton"; + this.amplitudeTestActionButton.Size = new System.Drawing.Size(150, 28); + this.amplitudeTestActionButton.TabIndex = 18; + this.amplitudeTestActionButton.Text = "Amplitude test"; // // btnCancel // @@ -239,6 +142,84 @@ this.txtLog.TabIndex = 5; this.txtLog.WordWrap = false; // + // button1 + // + this.button1.Location = new System.Drawing.Point(17, 28); + this.button1.Name = "button1"; + this.button1.Size = new System.Drawing.Size(150, 28); + this.button1.TabIndex = 108; + this.button1.Text = "Preadjustment init"; + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Location = new System.Drawing.Point(176, 121); + this.label1.Margin = new System.Windows.Forms.Padding(2, 0, 2, 0); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(22, 13); + this.label1.TabIndex = 109; + this.label1.Text = "--->"; + // + // label2 + // + this.label2.AutoSize = true; + this.label2.Location = new System.Drawing.Point(219, 155); + this.label2.Margin = new System.Windows.Forms.Padding(2, 0, 2, 0); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(22, 13); + this.label2.TabIndex = 110; + this.label2.Text = "--->"; + // + // label3 + // + this.label3.AutoSize = true; + this.label3.Location = new System.Drawing.Point(258, 189); + this.label3.Margin = new System.Windows.Forms.Padding(2, 0, 2, 0); + this.label3.Name = "label3"; + this.label3.Size = new System.Drawing.Size(22, 13); + this.label3.TabIndex = 111; + this.label3.Text = "--->"; + // + // label4 + // + this.label4.AutoSize = true; + this.label4.Location = new System.Drawing.Point(307, 223); + this.label4.Margin = new System.Windows.Forms.Padding(2, 0, 2, 0); + this.label4.Name = "label4"; + this.label4.Size = new System.Drawing.Size(22, 13); + this.label4.TabIndex = 112; + this.label4.Text = "--->"; + // + // label5 + // + this.label5.AutoSize = true; + this.label5.Location = new System.Drawing.Point(363, 257); + this.label5.Margin = new System.Windows.Forms.Padding(2, 0, 2, 0); + this.label5.Name = "label5"; + this.label5.Size = new System.Drawing.Size(22, 13); + this.label5.TabIndex = 113; + this.label5.Text = "--->"; + // + // label6 + // + this.label6.AutoSize = true; + this.label6.Location = new System.Drawing.Point(14, 87); + this.label6.Margin = new System.Windows.Forms.Padding(2, 0, 2, 0); + this.label6.Name = "label6"; + this.label6.Size = new System.Drawing.Size(117, 13); + this.label6.TabIndex = 114; + this.label6.Text = "Preadjustment process:"; + // + // label7 + // + this.label7.AutoSize = true; + this.label7.Location = new System.Drawing.Point(144, 87); + this.label7.Margin = new System.Windows.Forms.Padding(2, 0, 2, 0); + this.label7.Name = "label7"; + this.label7.Size = new System.Drawing.Size(22, 13); + this.label7.TabIndex = 115; + this.label7.Text = "--->"; + // // PreadjustmentActionsView // this.BackColor = System.Drawing.SystemColors.Control; @@ -254,18 +235,16 @@ } - private System.Windows.Forms.Button btnConnect; - private System.Windows.Forms.Button btnDisconnect; - private System.Windows.Forms.Button btnGetPcbId; - private System.Windows.Forms.Button readRegisterButton; - private System.Windows.Forms.TextBox writeRegisterValueTextBox; + private System.Windows.Forms.Button completionActionButton; + private System.Windows.Forms.Button offsetTestActionButton; + private System.Windows.Forms.Button amplitudeTestActionButton; + private System.Windows.Forms.Button button1; + private System.Windows.Forms.Label label5; + private System.Windows.Forms.Label label4; private System.Windows.Forms.Label label3; private System.Windows.Forms.Label label2; - private System.Windows.Forms.Button writeRegisterButton; - private System.Windows.Forms.Label label4; - private System.Windows.Forms.ComboBox writeRegisterNameComboBox; - private System.Windows.Forms.ComboBox readRegisterNameComboBox; - private System.Windows.Forms.Button btnLogin; - private System.Windows.Forms.Button btnCleanSlot; + private System.Windows.Forms.Label label1; + private System.Windows.Forms.Label label7; + private System.Windows.Forms.Label label6; } } \ No newline at end of file diff --git a/TBF/Rig/BridgeComponents/GciBridge/UI/StaraTuraAPI_GciBridge/PreadjustmentActionsView.cs b/TBF/Rig/BridgeComponents/GciBridge/UI/StaraTuraAPI_GciBridge/PreadjustmentActionsView.cs index fbd1b728a..bc3505b57 100644 --- a/TBF/Rig/BridgeComponents/GciBridge/UI/StaraTuraAPI_GciBridge/PreadjustmentActionsView.cs +++ b/TBF/Rig/BridgeComponents/GciBridge/UI/StaraTuraAPI_GciBridge/PreadjustmentActionsView.cs @@ -120,19 +120,15 @@ namespace TBF.Rig.BridgeComponents.GciBridge.UI.StaraTuraAPI_GciBridge Cursor = busy ? Cursors.WaitCursor : Cursors.Default; preparationActionButton.Enabled = !busy; - btnUpdateSlot.Enabled = !busy; detectActionButton.Enabled = !busy; - btnCleanAllSlots.Enabled = !busy; - btnGetPcbId.Enabled = !busy; - btnConnect.Enabled = !busy; - btnDisconnect.Enabled = !busy; - readRegisterButton.Enabled = !busy; - writeRegisterButton.Enabled = !busy; - readRegisterNameComboBox.Enabled = !busy; - writeRegisterNameComboBox.Enabled = !busy; - writeRegisterValueTextBox.Enabled = !busy; - btnLogin.Enabled = !busy; - btnCleanSlot.Enabled = !busy; + temperatureCalibrationActionButton.Enabled = !busy; + offsetTestActionButton.Enabled = !busy; + completionActionButton.Enabled = !busy; + amplitudeTestActionButton.Enabled = !busy; + amplitudeTestActionButton.Enabled = !busy; + temperatureCalibrationActionButton.Enabled = !busy; + offsetTestActionButton.Enabled = !busy; + completionActionButton.Enabled = !busy; btnCancel.Enabled = busy; } @@ -154,13 +150,7 @@ namespace TBF.Rig.BridgeComponents.GciBridge.UI.StaraTuraAPI_GciBridge private void LoadRegisterComboBoxes() { - var registers = _bridge.GetAllRegisterNames(); - readRegisterNameComboBox.Items.Clear(); - writeRegisterNameComboBox.Items.Clear(); - - readRegisterNameComboBox.Items.AddRange(registers.ToArray()); - writeRegisterNameComboBox.Items.AddRange(registers.ToArray()); } private void grpSlots_Enter(object sender, EventArgs e) @@ -281,6 +271,70 @@ namespace TBF.Rig.BridgeComponents.GciBridge.UI.StaraTuraAPI_GciBridge return settings; } + private void amplitudeTestActionButton_Click(object sender, EventArgs e) + { + ExecuteAsync(async token => + { + var pp = CreatePreparationProgress(); + + bool success = await _bridge.Preadjustment_AmplitudeTestAsync(pp, token); + + Log(success + ? "Amplitude Test completed." + : "Amplitude Test failed."); + + RefreshGrid(); + }); + } + + private void temperatureCalibrationActionButton_Click(object sender, EventArgs e) + { + ExecuteAsync(async token => + { + var pp = CreatePreparationProgress(); + + bool success = await _bridge.Preadjustment_TemperatureCalibrationAsync(pp, token); + + Log(success + ? "Temperature Calibration completed." + : "Temperature Calibration failed."); + + RefreshGrid(); + }); + } + + private void offsetTestActionButton_Click(object sender, EventArgs e) + { + ExecuteAsync(async token => + { + var pp = CreatePreparationProgress(); + + bool success = await _bridge.Preadjustment_OffsetTestAsync(pp, token); + + Log(success + ? "Offset Test completed." + : "Offset Test failed."); + + RefreshGrid(); + }); + } + + private void completionActionButton_Click(object sender, EventArgs e) + { + ExecuteAsync(async token => + { + var pp = CreatePreparationProgress(); + + bool success = await _bridge.Preadjustment_CompletionAsync(pp, token); + + Log(success + ? "Completion completed." + : "Completion failed."); + + RefreshGrid(); + }); + } + private void writeRegisterButton_Click(object sender, EventArgs e) { /*ExecuteAsync(async token => diff --git a/TBF/Rig/BridgeComponents/GciBridge/UI/StaraTuraAPI_GciBridge/SlotsComPortsRegistersActionsView.Designer.cs b/TBF/Rig/BridgeComponents/GciBridge/UI/StaraTuraAPI_GciBridge/SlotsComPortsRegistersActionsView.Designer.cs index 32a7ee738..ae6c642c4 100644 --- a/TBF/Rig/BridgeComponents/GciBridge/UI/StaraTuraAPI_GciBridge/SlotsComPortsRegistersActionsView.Designer.cs +++ b/TBF/Rig/BridgeComponents/GciBridge/UI/StaraTuraAPI_GciBridge/SlotsComPortsRegistersActionsView.Designer.cs @@ -42,6 +42,7 @@ this.btnGetSlot = new System.Windows.Forms.Button(); this.btnCleanAllSlots = new System.Windows.Forms.Button(); this.btnCleanSlot = new System.Windows.Forms.Button(); + this.writeRegisterValueTypeLabel = new System.Windows.Forms.Label(); this.btnCancel = new System.Windows.Forms.Button(); this.txtLog = new System.Windows.Forms.TextBox(); this.grpSlots.SuspendLayout(); @@ -49,6 +50,9 @@ // // grpSlots // + this.grpSlots.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); this.grpSlots.Controls.Add(this.writeRegisterNameComboBox); this.grpSlots.Controls.Add(this.readRegisterNameComboBox); this.grpSlots.Controls.Add(this.label4); @@ -66,9 +70,10 @@ this.grpSlots.Controls.Add(this.btnGetSlot); this.grpSlots.Controls.Add(this.btnCleanAllSlots); this.grpSlots.Controls.Add(this.btnCleanSlot); + this.grpSlots.Controls.Add(this.writeRegisterValueTypeLabel); this.grpSlots.Location = new System.Drawing.Point(10, 10); this.grpSlots.Name = "grpSlots"; - this.grpSlots.Size = new System.Drawing.Size(689, 304); + this.grpSlots.Size = new System.Drawing.Size(726, 304); this.grpSlots.TabIndex = 2; this.grpSlots.TabStop = false; this.grpSlots.Text = "Slots by selection in the table"; @@ -103,7 +108,7 @@ // this.writeRegisterValueTextBox.Location = new System.Drawing.Point(555, 264); this.writeRegisterValueTextBox.Name = "writeRegisterValueTextBox"; - this.writeRegisterValueTextBox.Size = new System.Drawing.Size(117, 20); + this.writeRegisterValueTextBox.Size = new System.Drawing.Size(85, 20); this.writeRegisterValueTextBox.TabIndex = 12; // // label3 @@ -223,6 +228,15 @@ this.btnCleanSlot.Text = "CleanSlot(slot)"; this.btnCleanSlot.Click += new System.EventHandler(this.btnCleanSlot_Click); // + // writeRegisterValueTypeLabel + // + this.writeRegisterValueTypeLabel.AutoSize = true; + this.writeRegisterValueTypeLabel.Location = new System.Drawing.Point(646, 267); + this.writeRegisterValueTypeLabel.Name = "writeRegisterValueTypeLabel"; + this.writeRegisterValueTypeLabel.Size = new System.Drawing.Size(36, 13); + this.writeRegisterValueTypeLabel.TabIndex = 19; + this.writeRegisterValueTypeLabel.Text = "type: -"; + // // btnCancel // this.btnCancel.Enabled = false; @@ -243,18 +257,18 @@ this.txtLog.Name = "txtLog"; this.txtLog.ReadOnly = true; this.txtLog.ScrollBars = System.Windows.Forms.ScrollBars.Both; - this.txtLog.Size = new System.Drawing.Size(689, 232); + this.txtLog.Size = new System.Drawing.Size(726, 232); this.txtLog.TabIndex = 5; this.txtLog.WordWrap = false; // - // GenesisCordonelInterfaceView + // SlotsComPortsRegistersActionsView // this.BackColor = System.Drawing.SystemColors.Control; this.Controls.Add(this.grpSlots); this.Controls.Add(this.btnCancel); this.Controls.Add(this.txtLog); - this.Name = "GenesisCordonelInterfaceView"; - this.Size = new System.Drawing.Size(719, 603); + this.Name = "SlotsComPortsRegistersActionsView"; + this.Size = new System.Drawing.Size(756, 603); this.grpSlots.ResumeLayout(false); this.grpSlots.PerformLayout(); this.ResumeLayout(false); @@ -275,5 +289,6 @@ private System.Windows.Forms.ComboBox readRegisterNameComboBox; private System.Windows.Forms.Button btnLogin; private System.Windows.Forms.Button btnCleanSlot; + private System.Windows.Forms.Label writeRegisterValueTypeLabel; } } \ No newline at end of file diff --git a/TBF/Rig/BridgeComponents/GciBridge/UI/StaraTuraAPI_GciBridge/SlotsComPortsRegistersActionsView.cs b/TBF/Rig/BridgeComponents/GciBridge/UI/StaraTuraAPI_GciBridge/SlotsComPortsRegistersActionsView.cs index eb9331d09..0050571d7 100644 --- a/TBF/Rig/BridgeComponents/GciBridge/UI/StaraTuraAPI_GciBridge/SlotsComPortsRegistersActionsView.cs +++ b/TBF/Rig/BridgeComponents/GciBridge/UI/StaraTuraAPI_GciBridge/SlotsComPortsRegistersActionsView.cs @@ -17,6 +17,8 @@ namespace TBF.Rig.BridgeComponents.GciBridge.UI.StaraTuraAPI_GciBridge private CancellationTokenSource _cts; private readonly Action _addSlotAction; private readonly Action _saveAction; + private readonly Dictionary _registerTypes = + new Dictionary(StringComparer.OrdinalIgnoreCase); public SlotsComPortsRegistersActionsView( MainView mainview, @@ -33,6 +35,13 @@ namespace TBF.Rig.BridgeComponents.GciBridge.UI.StaraTuraAPI_GciBridge InitializeComponent(); LoadRegisterComboBoxes(); + + _mainView._batchPanel.SelectedSlotsChanged -= LoadRegisterComboBoxes; + _mainView._batchPanel.SelectedSlotsChanged += LoadRegisterComboBoxes; + writeRegisterNameComboBox.SelectedIndexChanged -= writeRegisterNameComboBox_SelectedIndexChanged; + writeRegisterNameComboBox.SelectedIndexChanged += writeRegisterNameComboBox_SelectedIndexChanged; + writeRegisterNameComboBox.TextChanged -= writeRegisterNameComboBox_SelectedIndexChanged; + writeRegisterNameComboBox.TextChanged += writeRegisterNameComboBox_SelectedIndexChanged; } private void AddSlot() @@ -48,14 +57,14 @@ namespace TBF.Rig.BridgeComponents.GciBridge.UI.StaraTuraAPI_GciBridge private List GetSelectedSlots() { if (_mainView == null || _mainView._batchPanel == null) - throw new Exception("Meter batch grid is not available."); + { + Log("Meter batch grid is not available."); - var slots = _mainView._batchPanel.GetSelectedGridData(); + return new List(); + } - if (slots.Count == 0) - throw new Exception("No selected slots in grid."); - - return slots; + return _mainView._batchPanel.GetSelectedGridData() + ?? new List(); } private void RefreshGrid(int? removedSlot = null) @@ -414,16 +423,7 @@ namespace TBF.Rig.BridgeComponents.GciBridge.UI.StaraTuraAPI_GciBridge if (string.IsNullOrWhiteSpace(valueText)) throw new Exception("Write register value is empty."); - object value; - - if (registerName == "GENESISFLOW_LedMode") - { - value = byte.Parse(valueText); - } - else - { - value = valueText; - } + object value = ConvertTextToRegisterValue(registerName, valueText); var tasks = GetSelectedSlots() .Select(async slot => @@ -530,18 +530,162 @@ namespace TBF.Rig.BridgeComponents.GciBridge.UI.StaraTuraAPI_GciBridge private void LoadRegisterComboBoxes() { - var registers = _bridge.GetAllRegisterNames(); + _registerTypes.Clear(); readRegisterNameComboBox.Items.Clear(); writeRegisterNameComboBox.Items.Clear(); - readRegisterNameComboBox.Items.AddRange(registers.ToArray()); - writeRegisterNameComboBox.Items.AddRange(registers.ToArray()); + var selectedSlots = GetSelectedSlots(); + + if (selectedSlots.Count == 0) + { + Log("No selected slot."); + return; + } + + int slot = selectedSlots + .OrderBy(x => x.Slot) + .First() + .Slot; + + var registers = _mainView._laatzenApi.GetRegistersDicForSlot(slot); + + var uniqueRegisters = registers + .GroupBy(x => x.Key.GetIdent()) + .Select(g => g.First()) + .OrderBy(x => x.Key.GetIdent()) + .ToList(); + + foreach (var item in uniqueRegisters) + { + string registerName = item.Key.GetIdent(); + Type dataType = item.Key.DataType; + + _registerTypes[registerName] = dataType; + + readRegisterNameComboBox.Items.Add(registerName); + writeRegisterNameComboBox.Items.Add(registerName); + } + + Log($"Loaded {uniqueRegisters.Count} unique registers from slot {slot}"); } private void grpSlots_Enter(object sender, EventArgs e) { } + + private void writeRegisterNameComboBox_SelectedIndexChanged(object sender, EventArgs e) + { + string registerName = Convert.ToString(writeRegisterNameComboBox.Text).Trim(); + + if (_registerTypes.TryGetValue(registerName, out var type)) + { + writeRegisterValueTypeLabel.Text = $"type: {type.Name}"; + } + else + { + writeRegisterValueTypeLabel.Text = "type: -"; + } + } + + private object ConvertTextToRegisterValue( + string registerName, + string valueText) + { + if (!_registerTypes.TryGetValue( + registerName, + out var targetType)) + { + throw new Exception( + $"Unknown register type for register '{registerName}'."); + } + + return ConvertTextToType( + valueText, + targetType, + registerName); + } + + private object ConvertTextToType( + string valueText, + Type targetType, + string registerName) + { + if (targetType == typeof(string)) + return valueText; + + if (targetType.IsEnum) + { + return Enum.Parse( + targetType, + valueText, + true); + } + + if (targetType == typeof(byte[])) + { + return ParseByteArray(valueText); + } + + if (targetType.Name == "Enum8") + { + return byte.Parse(valueText); + } + + try + { + return Convert.ChangeType( + valueText, + targetType, + System.Globalization.CultureInfo.InvariantCulture); + } + catch (Exception ex) + { + throw new Exception( + $"Value '{valueText}' cannot be converted to '{targetType.Name}' for register '{registerName}'.", + ex); + } + } + + private byte[] ParseByteArray(string valueText) + { + valueText = valueText.Trim(); + + if (valueText.Contains("-") || + valueText.Contains(" ")) + { + return valueText + .Split( + new[] { '-', ' ', ',', ';' }, + StringSplitOptions.RemoveEmptyEntries) + .Select(x => x.Replace("0x", "")) + .Select(x => Convert.ToByte(x, 16)) + .ToArray(); + } + + valueText = + valueText.Replace("0x", ""); + + if (valueText.Length % 2 != 0) + { + throw new Exception( + "Hex string length must be even."); + } + + byte[] result = + new byte[valueText.Length / 2]; + + for (int i = 0; i < result.Length; i++) + { + string hex = + valueText.Substring(i * 2, 2); + + result[i] = + Convert.ToByte(hex, 16); + } + + return result; + } } } \ No newline at end of file diff --git a/TBF/TBF.csproj b/TBF/TBF.csproj index 2eaeb68a6..a98f0bdee 100644 --- a/TBF/TBF.csproj +++ b/TBF/TBF.csproj @@ -4450,6 +4450,10 @@ {d0c8d887-ed52-40ab-a069-90bce0e801e2} CordonelPreadjustmentUi + + {f4aaf7e6-7333-4284-b735-e32deb076c64} + Registers + {6d2777bb-7a88-466d-a49b-3266f9bf0160} ProductionOrderCore From 9700ba7900baff124990e872f1868e98b5bf8584 Mon Sep 17 00:00:00 2001 From: Marek Frniak Date: Fri, 22 May 2026 08:52:40 +0200 Subject: [PATCH 4/4] Develop - GciBridge -> GCI -> PreadjustmentUI functions 3 --- .../API/InterfaceGCIToLaatzen.cs | 708 ++++++++++++------ .../API/InterfaceOutsideToGCI.cs | 29 +- GenesisCordonelInterface/API/PublicModels.cs | 36 + .../BridgeComponents/GciBridge/GciBridge.cs | 131 +++- .../UI/Debug/MeterBatchConfigPanel.cs | 12 +- .../PreadjustmentActionsView.cs | 193 ++--- .../SlotsComPortsRegistersActionsView.cs | 4 +- 7 files changed, 754 insertions(+), 359 deletions(-) diff --git a/GenesisCordonelInterface/API/InterfaceGCIToLaatzen.cs b/GenesisCordonelInterface/API/InterfaceGCIToLaatzen.cs index 510c87cf0..47b4f10f1 100644 --- a/GenesisCordonelInterface/API/InterfaceGCIToLaatzen.cs +++ b/GenesisCordonelInterface/API/InterfaceGCIToLaatzen.cs @@ -9,6 +9,7 @@ using NLog.Fluent; using System; using System.Collections.Concurrent; using System.Collections.Generic; +using System.Configuration; using System.Drawing; using System.Linq; using System.Reflection; @@ -21,6 +22,7 @@ using Xylem.Common.Hardware.Interfaces.Ports.PortCore.EventArguments; using Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore; using Xylem.Common.Hardware.WaterMeter.Genesis.Registers; using Xylem.Common.Hardware.WaterMeter.WaterMeterCore; +using Xylem.Common.Hardware.WaterMeter.WaterMeterCore.Consts; using Xylem.Common.Hardware.WaterMeter.WaterMeterRegisters; using Xylem.Common.Ui.CordonelPreadjustmentUi; using static GenesisCordonelInterface.API.PublicModels; @@ -93,13 +95,13 @@ namespace GenesisCordonelInterface.API /// public List GetMeterBatchDebugStatuses() { - List meters; + List meters; //just snapshot of list under lock lock (_meterBatchLock) { meters = _meterBatch.ListOfMeters - .OfType() + .OfType() .ToList(); } @@ -167,7 +169,7 @@ namespace GenesisCordonelInterface.API lock (_meterBatchLock) { return _meterBatch.ListOfMeters - .OfType() + .OfType() .FirstOrDefault(m => m.Slot == slot); } } @@ -208,7 +210,7 @@ namespace GenesisCordonelInterface.API { lock (_meterBatchLock) { - foreach (var meter in _meterBatch.ListOfMeters.OfType()) + foreach (var meter in _meterBatch.ListOfMeters.OfType()) { meter.DisposeMeter(); } @@ -370,7 +372,7 @@ namespace GenesisCordonelInterface.API PortConfig? req, PortConfig? str) { - GenesisMeter meter = new GenesisMeter(); + ZeroFlowGenesisMeter meter = new ZeroFlowGenesisMeter(0, 3, !(_meterControls is TempMeterStateControl), useForPreadjustmentUI: false); meter.Slot = slot; @@ -379,7 +381,8 @@ namespace GenesisCordonelInterface.API meter.requestPortConfig = req; meter.streamingPortConfig = str; - //meter.SetupGenesisMeter(slot, req, str, true); + meter.onlineOperation = false; + lock (_meterBatchLock) { _meterBatch.AddMeter2(meter); @@ -1523,69 +1526,88 @@ namespace GenesisCordonelInterface.API #region ================================== PreAdjustmentUI DETECT process ================================== - public Task Preadjustment_DetectAsync( + public Task Preadjustment_DetectAsync( CancellationToken token = default) - { - return Task.Run(() => Preadjustment_DetectCore( - token), - token); + { + return Task.Run(() => Preadjustment_DetectCore(token), token); } - private bool Preadjustment_DetectCore( - CancellationToken token) + private PreadjustmentDetectResult Preadjustment_DetectCore( + CancellationToken token) { - MeterBatch globalMeterBatch = new MeterBatch(); - MeterBatch thermoMeterBatch = new MeterBatch(); + const string operation = nameof(Preadjustment_DetectCore); - if (globalMeterBatch == null) - throw new ArgumentNullException(nameof(globalMeterBatch)); + try + { + MeterBatch globalMeterBatch = new MeterBatch(); + MeterBatch thermoMeterBatch = new MeterBatch(); - if (thermoMeterBatch == null) - throw new ArgumentNullException(nameof(thermoMeterBatch)); + if (_settings == null) + throw new ArgumentNullException(nameof(_settings)); - if (_settings == null) - throw new ArgumentNullException(nameof(_settings)); + if (_meterControls == null) + throw new ArgumentNullException(nameof(_meterControls)); - if (_meterControls == null) - throw new ArgumentNullException(nameof(_meterControls)); + if (_tempMeterControls == null) + _tempMeterControls = new List(); - if (_tempMeterControls == null) - _tempMeterControls = new List(); + if (globalMeterBatch.ListOfMeters.Any()) + globalMeterBatch.RemoveAllMeters(); - // Clear previous batch content - if (globalMeterBatch.ListOfMeters.Any()) - globalMeterBatch.RemoveAllMeters(); + if (thermoMeterBatch.ListOfMeters.Any()) + thermoMeterBatch.RemoveAllMeters(); - if (thermoMeterBatch.ListOfMeters.Any()) - thermoMeterBatch.RemoveAllMeters(); + globalMeterBatch = _meterBatch; - globalMeterBatch = _meterBatch; + if (!_settings.GetTempUseTempFlansh()) + _tempMeterControls.Clear(); - // If manual temperature input is used, - // ignore temporary meter controls - if (!_settings.GetTempUseTempFlansh()) - _tempMeterControls.Clear(); + var allMeterControls = new List(); - var allMeterControls = - new List(); + allMeterControls.AddRange(_meterControls); + allMeterControls.AddRange(_tempMeterControls); - allMeterControls.AddRange(_meterControls); - allMeterControls.AddRange(_tempMeterControls); + CreateZeroFlowMeters( + globalMeterBatch, + thermoMeterBatch, + allMeterControls, + token); - CreateZeroFlowMeters(globalMeterBatch, thermoMeterBatch, allMeterControls, token); + SetEnableOpeningState(allMeterControls); - SetEnableOpeningState(allMeterControls); + if (!_meterControls.Any(a => a.EnableOpening)) + { + return new PreadjustmentDetectResult + { + Success = false, + DetectedMeterCount = 0, + DetectedThermometerCount = _tempMeterControls.Count(t => t.IsEnabled), + ErrorMessage = "No enabled meter found." + }; + } - if (!_meterControls.Any(a => a.EnableOpening)) - return false; + SetUnknownStatus(allMeterControls); - SetUnknownStatus(allMeterControls); + CheckTemperatureMeters( + _settings, + _tempMeterControls, + token); - //CheckNormalMeters( meterControls, token); //open ports - - CheckTemperatureMeters(_settings, _tempMeterControls, token); - - return true; + return new PreadjustmentDetectResult + { + Success = true, + DetectedMeterCount = _meterControls.Count(m => m.IsEnabled), + DetectedThermometerCount = _tempMeterControls.Count(t => t.IsEnabled) + }; + } + catch (Exception ex) + { + return new PreadjustmentDetectResult + { + Success = false, + ErrorMessage = ex.Message + }; + } } private void CreateZeroFlowMeters( @@ -1702,246 +1724,494 @@ namespace GenesisCordonelInterface.API #endregion #region ================================== PreAdjustmentUI PREPARATION process ================================== - - /// - /// Execute standalone preparation process. - /// - /// Flow: - /// - /// Create ProcessProgress - /// ↓ - /// Create PreparationProcess - /// ↓ - /// Start process - /// ↓ - /// Wait for completion - /// ↓ - /// Return result - /// - /// Notes: - /// - GUI independent - /// - reusable from GCI workflow - /// - supports SinglePath and MultiPath mode - /// - public Task Preadjustment_PreparationAsync( + public Task Preadjustment_PreparationAsync( + int slot, ProcessProgress pp, CancellationToken token = default) { - IProcess process; + return GetWorker(slot).RunAsync( + () => Preadjustment_Preparation(slot, pp), + token); + } + /// + /// Executes standalone preparation process. + /// + public PreadjustmentProcessResult Preadjustment_Preparation( + int slot, + ProcessProgress pp) + { + const string operation = nameof(Preadjustment_Preparation); + + try + { + LogInfo(operation, $"Start. Slot={slot}"); + + var meter = GetMeterThreadSafe(slot); + EnsureConnected(meter); + + BaseProcess process = + CreatePreparationProcess(pp); + + bool success = + ExecuteProcess(process, pp); + + var result = + new PreadjustmentProcessResult + { + Success = success, + Slot = slot, + ProcessName = process.ProcessName, + ErrorMessage = success + ? null + : process.FailedMessage + }; + + LogInfo(operation, result.ToString()); + + return result; + } + catch (Exception ex) + { + LogError(operation, ex); + + return new PreadjustmentProcessResult + { + Success = false, + Slot = slot, + ProcessName = "Preparation", + ErrorMessage = ex.Message + }; + } + } + + /// + /// Creates preparation process instance based on current configuration. + /// + /// Current process progress context + /// Configured preparation process + private BaseProcess CreatePreparationProcess(ProcessProgress pp) + { if (pp.Setting.NumberOfPaths == 1) { - process = - new SPPreparationProcess( - "Preparation Single", - PreAdjustmentControl.StatusPanelItems.Prepare, - PreAdjustmentControl.PredefinedMessages.WaitUntilPreparationFinished(pp.Setting.Culture), - PreAdjustmentControl.PredefinedMessages.PreparationFailed(pp.Setting.Culture), - 60); - } - else - { - process = - new PreparationProcess( - "Preparation", - PreAdjustmentControl.StatusPanelItems.Prepare, - PreAdjustmentControl.PredefinedMessages.WaitUntilPreparationFinished(pp.Setting.Culture), - PreAdjustmentControl.PredefinedMessages.PreparationFailed(pp.Setting.Culture), - 60); + return new SPPreparationProcess( + "Preparation Single", + PreAdjustmentControl.StatusPanelItems.Prepare, + PreAdjustmentControl.PredefinedMessages.WaitUntilPreparationFinished(pp.Setting.Culture), + PreAdjustmentControl.PredefinedMessages.PreparationFailed(pp.Setting.Culture), + 60); } - return ExecuteProcessAsync( - process, - pp, - token); + return new PreparationProcess( + "Preparation", + PreAdjustmentControl.StatusPanelItems.Prepare, + PreAdjustmentControl.PredefinedMessages.WaitUntilPreparationFinished(pp.Setting.Culture), + PreAdjustmentControl.PredefinedMessages.PreparationFailed(pp.Setting.Culture), + 60); } #endregion #region ================================== PreAdjustmentUI AMPLITUDE TEST process ================================== - - /// - /// Execute standalone amplitude test process. - /// - public Task Preadjustment_AmplitudeTestAsync( + public Task Preadjustment_AmplitudeTestAsync( + int slot, ProcessProgress pp, CancellationToken token = default) { - if (pp.Setting.TempOnly) - return Task.FromResult(true); + return GetWorker(slot).RunAsync( + () => Preadjustment_AmplitudeTest(slot, pp), + token); + } - IProcess process; + public PreadjustmentProcessResult Preadjustment_AmplitudeTest( + int slot, + ProcessProgress pp) + { + const string operation = nameof(Preadjustment_AmplitudeTest); + try + { + LogInfo(operation, $"Start. Slot={slot}"); + + var meter = GetMeterThreadSafe(slot); + EnsureConnected(meter); + + if (pp.Setting.TempOnly) + { + return new PreadjustmentProcessResult + { + Success = true, + Slot = slot, + ProcessName = "Amplitude Test" + }; + } + + BaseProcess process = CreateAmplitudeTestProcess(pp); + + bool success = ExecuteProcess(process, pp); + + LogInfo(operation, $"Finished. Slot={slot}, Success={success}"); + + return new PreadjustmentProcessResult + { + Success = success, + Slot = slot, + ProcessName = process.ProcessName, + ErrorMessage = success ? null : process.FailedMessage + }; + } + catch (Exception ex) + { + LogError(operation, ex); + + return new PreadjustmentProcessResult + { + Success = false, + Slot = slot, + ProcessName = "Amplitude Test", + ErrorMessage = ex.Message + }; + } + } + + /// + /// Creates amplitude test process instance based on current configuration. + /// + /// Current process progress context + /// Configured amplitude test process + private BaseProcess CreateAmplitudeTestProcess(ProcessProgress pp) + { if (pp.Setting.NumberOfPaths == 1) { - process = - new SPAmplitudeTestProcess( - "Amplitude Test Single", - PreAdjustmentControl.StatusPanelItems.Amplitude, - PreAdjustmentControl.PredefinedMessages.WaitUntilAmplitudeTestFinished(pp.Setting.Culture), - PreAdjustmentControl.PredefinedMessages.AmplitudeFailed(pp.Setting.Culture), - 4 * 60); - } - else - { - process = - new AmplitudeTestProcess( - "Amplitude Test", - PreAdjustmentControl.StatusPanelItems.Amplitude, - PreAdjustmentControl.PredefinedMessages.WaitUntilAmplitudeTestFinished(pp.Setting.Culture), - PreAdjustmentControl.PredefinedMessages.AmplitudeFailed(pp.Setting.Culture), - 4 * 60); + return new SPAmplitudeTestProcess( + "Amplitude Test Single", + PreAdjustmentControl.StatusPanelItems.Amplitude, + PreAdjustmentControl.PredefinedMessages.WaitUntilAmplitudeTestFinished(pp.Setting.Culture), + PreAdjustmentControl.PredefinedMessages.AmplitudeFailed(pp.Setting.Culture), + 4 * 60); } - return ExecuteProcessAsync( - process, - pp, - token); + return new AmplitudeTestProcess( + "Amplitude Test", + PreAdjustmentControl.StatusPanelItems.Amplitude, + PreAdjustmentControl.PredefinedMessages.WaitUntilAmplitudeTestFinished(pp.Setting.Culture), + PreAdjustmentControl.PredefinedMessages.AmplitudeFailed(pp.Setting.Culture), + 4 * 60); } #endregion #region ================================== PreAdjustmentUI TEMPERATURE CALIBRATION process ================================== - public Task Preadjustment_TemperatureCalibrationAsync( + public Task Preadjustment_TemperatureCalibrationAsync( + int slot, ProcessProgress pp, CancellationToken token = default) { - IProcess process; + return GetWorker(slot).RunAsync( + () => Preadjustment_TemperatureCalibration(slot, pp), + token); + } + public PreadjustmentProcessResult Preadjustment_TemperatureCalibration( + int slot, + ProcessProgress pp) + { + const string operation = + nameof(Preadjustment_TemperatureCalibration); + + try + { + LogInfo(operation, $"Start. Slot={slot}"); + + var meter = + GetMeterThreadSafe(slot); + + EnsureConnected(meter); + + BaseProcess process = + CreateTemperatureCalibrationProcess(pp); + + bool success = + ExecuteProcess(process, pp); + + var result = + new PreadjustmentProcessResult + { + Success = success, + Slot = slot, + ProcessName = process.ProcessName, + ErrorMessage = success + ? null + : process.FailedMessage + }; + + LogInfo(operation, result.ToString()); + + return result; + } + catch (Exception ex) + { + LogError(operation, ex); + + return new PreadjustmentProcessResult + { + Success = false, + Slot = slot, + ProcessName = "Temperature Calibration", + ErrorMessage = ex.Message + }; + } + } + + /// + /// Creates temperature calibration process instance based on current configuration. + /// + /// Current process progress context + /// Configured temperature calibration process + private BaseProcess CreateTemperatureCalibrationProcess(ProcessProgress pp) + { if (pp.Setting.NumberOfPaths == 1) { - process = - new SPTemperatureCalibrationProcess( - "Temperature Calibration Single", - PreAdjustmentControl.StatusPanelItems.TempCal, - PreAdjustmentControl.PredefinedMessages.WaitUntilTemperatureCalibrationFinished(pp.Setting.Culture), - PreAdjustmentControl.PredefinedMessages.TempCalFailed(pp.Setting.Culture), - 2 * 60); - } - else - { - process = - new TemperatureCalibrationProcess( - "Temperature Calibration", - PreAdjustmentControl.StatusPanelItems.TempCal, - PreAdjustmentControl.PredefinedMessages.WaitUntilTemperatureCalibrationFinished(pp.Setting.Culture), - PreAdjustmentControl.PredefinedMessages.TempCalFailed(pp.Setting.Culture), - 2 * 60); + return new SPTemperatureCalibrationProcess( + "Temperature Calibration Single", + PreAdjustmentControl.StatusPanelItems.TempCal, + PreAdjustmentControl.PredefinedMessages.WaitUntilTemperatureCalibrationFinished(pp.Setting.Culture), + PreAdjustmentControl.PredefinedMessages.TempCalFailed(pp.Setting.Culture), + 2 * 60); } - return ExecuteProcessAsync( - process, - pp, - token); + return new TemperatureCalibrationProcess( + "Temperature Calibration", + PreAdjustmentControl.StatusPanelItems.TempCal, + PreAdjustmentControl.PredefinedMessages.WaitUntilTemperatureCalibrationFinished(pp.Setting.Culture), + PreAdjustmentControl.PredefinedMessages.TempCalFailed(pp.Setting.Culture), + 2 * 60); } #endregion #region ================================== PreAdjustmentUI OFFSET TEST process ================================== - public Task Preadjustment_OffsetTestAsync( - ProcessProgress pp, - CancellationToken token = default) + public Task Preadjustment_OffsetTestAsync( + int slot, + ProcessProgress pp, + CancellationToken token = default) { - if (pp.Setting.TempOnly) - return Task.FromResult(true); + return GetWorker(slot).RunAsync( + () => Preadjustment_OffsetTest(slot, pp), + token); + } - IProcess process; + public PreadjustmentProcessResult Preadjustment_OffsetTest( + int slot, + ProcessProgress pp) + { + const string operation = + nameof(Preadjustment_OffsetTest); + try + { + LogInfo(operation, $"Start. Slot={slot}"); + + var meter = + GetMeterThreadSafe(slot); + + EnsureConnected(meter); + + if (pp.Setting.TempOnly) + { + return new PreadjustmentProcessResult + { + Success = true, + Slot = slot, + ProcessName = "Offset Test" + }; + } + + BaseProcess process = + CreateOffsetTestProcess(pp); + + bool success = + ExecuteProcess(process, pp); + + var result = + new PreadjustmentProcessResult + { + Success = success, + Slot = slot, + ProcessName = process.ProcessName, + ErrorMessage = success + ? null + : process.FailedMessage + }; + + LogInfo(operation, result.ToString()); + + return result; + } + catch (Exception ex) + { + LogError(operation, ex); + + return new PreadjustmentProcessResult + { + Success = false, + Slot = slot, + ProcessName = "Offset Test", + ErrorMessage = ex.Message + }; + } + } + + /// + /// Creates offset test process instance based on current configuration. + /// + /// Current process progress context + /// Configured offset test process + private BaseProcess CreateOffsetTestProcess(ProcessProgress pp) + { if (pp.Setting.NumberOfPaths == 1) { - process = - new SPOffsetTestProcess( - "Offset Test Single", - PreAdjustmentControl.StatusPanelItems.Offset, - PreAdjustmentControl.PredefinedMessages.WaitUntilZeroflowOffsetTestFinished(pp.Setting.Culture), - PreAdjustmentControl.PredefinedMessages.ZeroflowOffsetTestFailed(pp.Setting.Culture), - 18 * 60); - } - else - { - process = - new OffsetTestProcess( - "Offset Test", - PreAdjustmentControl.StatusPanelItems.Offset, - PreAdjustmentControl.PredefinedMessages.WaitUntilZeroflowOffsetTestFinished(pp.Setting.Culture), - PreAdjustmentControl.PredefinedMessages.ZeroflowOffsetTestFailed(pp.Setting.Culture), - 18 * 60); + return new SPOffsetTestProcess( + "Offset Test Single", + PreAdjustmentControl.StatusPanelItems.Offset, + PreAdjustmentControl.PredefinedMessages.WaitUntilZeroflowOffsetTestFinished(pp.Setting.Culture), + PreAdjustmentControl.PredefinedMessages.ZeroflowOffsetTestFailed(pp.Setting.Culture), + 18 * 60); } - return ExecuteProcessAsync( - process, - pp, - token); + return new OffsetTestProcess( + "Offset Test", + PreAdjustmentControl.StatusPanelItems.Offset, + PreAdjustmentControl.PredefinedMessages.WaitUntilZeroflowOffsetTestFinished(pp.Setting.Culture), + PreAdjustmentControl.PredefinedMessages.ZeroflowOffsetTestFailed(pp.Setting.Culture), + 18 * 60); } #endregion #region ================================== PreAdjustmentUI COMPLETION process ================================== - public Task Preadjustment_CompletionAsync( + public Task Preadjustment_CompletionAsync( + int slot, ProcessProgress pp, CancellationToken token = default) { - IProcess process; - - if (pp.Setting.NumberOfPaths == 1) - { - process = - new SPCompletionProcess( - "Completion Single", - PreAdjustmentControl.StatusPanelItems.Completion, - PreAdjustmentControl.PredefinedMessages.WaitUntilCompletionFinished(pp.Setting.Culture), - PreAdjustmentControl.PredefinedMessages.CompletionFailed(pp.Setting.Culture), - 1 * 60); - } - else - { - process = - new CompletionProcess( - "Completion", - PreAdjustmentControl.StatusPanelItems.Completion, - PreAdjustmentControl.PredefinedMessages.WaitUntilCompletionFinished(pp.Setting.Culture), - PreAdjustmentControl.PredefinedMessages.CompletionFailed(pp.Setting.Culture), - 1 * 60); - } - - return ExecuteProcessAsync( - process, - pp, + return GetWorker(slot).RunAsync( + () => Preadjustment_Completion(slot, pp), token); } - #endregion - - #region ================================== PreAdjustmentUI process threading ================================== - - public async Task ExecuteProcessAsync( - IProcess process, - ProcessProgress pp, - CancellationToken token = default) + public PreadjustmentProcessResult Preadjustment_Completion( + int slot, + ProcessProgress pp) { - return await Task.Run(() => + const string operation = + nameof(Preadjustment_Completion); + + try { - pp.IsBusy = true; + LogInfo(operation, $"Start. Slot={slot}"); - process.StartProcess( - pp, - _meterControls, - _tempMeterControls); + var meter = + GetMeterThreadSafe(slot); - while (pp.IsBusy && !token.IsCancellationRequested) + EnsureConnected(meter); + + BaseProcess process = + CreateCompletionProcess(pp); + + bool success = + ExecuteProcess(process, pp); + + var result = + new PreadjustmentProcessResult + { + Success = success, + Slot = slot, + ProcessName = process.ProcessName, + ErrorMessage = success + ? null + : process.FailedMessage + }; + + LogInfo(operation, result.ToString()); + + return result; + } + catch (Exception ex) + { + LogError(operation, ex); + + return new PreadjustmentProcessResult { - Thread.Sleep(50); - } + Success = false, + Slot = slot, + ProcessName = "Completion", + ErrorMessage = ex.Message + }; + } + } - return !_meterControls.Any( - m => m.IsEnabled && m.Failed); + /// + /// Creates completion process instance based on current configuration. + /// + /// Current process progress context + /// Configured completion process + private BaseProcess CreateCompletionProcess(ProcessProgress pp) + { + if (pp.Setting.NumberOfPaths == 1) + { + return new SPCompletionProcess( + "Completion Single", + PreAdjustmentControl.StatusPanelItems.Completion, + PreAdjustmentControl.PredefinedMessages.WaitUntilCompletionFinished(pp.Setting.Culture), + PreAdjustmentControl.PredefinedMessages.CompletionFailed(pp.Setting.Culture), + 1 * 60); + } - }, token); + return new CompletionProcess( + "Completion", + PreAdjustmentControl.StatusPanelItems.Completion, + PreAdjustmentControl.PredefinedMessages.WaitUntilCompletionFinished(pp.Setting.Culture), + PreAdjustmentControl.PredefinedMessages.CompletionFailed(pp.Setting.Culture), + 1 * 60); } #endregion + + #region ================================== PreAdjustmentUI ExecuteProcess ================================== + private bool ExecuteProcess( + BaseProcess process, + ProcessProgress pp) + { + pp.IsBusy = true; + + process.StartProcess( + pp, + _meterControls, + _tempMeterControls); + + while (pp.IsBusy && !pp.StopSequence) + { + Thread.Sleep(50); + } + + foreach (var meterCtrl in _meterControls) + { + if (meterCtrl.IsEnabled && meterCtrl.Failed) + { + pp.GenerateReturnNote(process.FailedMessage, meterCtrl); + meterCtrl.IsEnabled = false; + } + } + + if (pp.StopSequence) + return false; + + return _meterControls.Any(m => m.IsEnabled && !m.Failed); + } + #endregion } } \ No newline at end of file diff --git a/GenesisCordonelInterface/API/InterfaceOutsideToGCI.cs b/GenesisCordonelInterface/API/InterfaceOutsideToGCI.cs index 7082ea5ad..e6ce41cea 100644 --- a/GenesisCordonelInterface/API/InterfaceOutsideToGCI.cs +++ b/GenesisCordonelInterface/API/InterfaceOutsideToGCI.cs @@ -456,47 +456,50 @@ namespace GenesisCordonelInterface.API // Preadjustment - public Task Preadjustment_DetectAsync( + public Task Preadjustment_DetectAsync( CancellationToken token = default) { return _innerMeterAPI.Preadjustment_DetectAsync(token); } - public Task Preadjustment_PreparationAsync( + public Task Preadjustment_PreparationAsync( + int slot, ProcessProgress pp, CancellationToken token = default) { - return _innerMeterAPI.Preadjustment_PreparationAsync(pp, token); + return _innerMeterAPI.Preadjustment_PreparationAsync(slot, pp, token); } - public Task Preadjustment_AmplitudeTestAsync( + public Task Preadjustment_AmplitudeTestAsync( + int slot, ProcessProgress pp, CancellationToken token = default) { - return _innerMeterAPI.Preadjustment_AmplitudeTestAsync(pp, token); + return _innerMeterAPI.Preadjustment_AmplitudeTestAsync(slot, pp, token); } - public Task Preadjustment_TemperatureCalibrationAsync( + public Task Preadjustment_TemperatureCalibrationAsync( + int slot, ProcessProgress pp, CancellationToken token = default) { - return _innerMeterAPI.Preadjustment_TemperatureCalibrationAsync(pp, token); + return _innerMeterAPI.Preadjustment_TemperatureCalibrationAsync(slot, pp, token); } - public Task Preadjustment_OffsetTestAsync( + public Task Preadjustment_OffsetTestAsync( + int slot, ProcessProgress pp, CancellationToken token = default) { - return _innerMeterAPI.Preadjustment_OffsetTestAsync(pp, token); + return _innerMeterAPI.Preadjustment_OffsetTestAsync(slot, pp, token); } - public Task Preadjustment_CompletionAsync( + public Task Preadjustment_CompletionAsync( + int slot, ProcessProgress pp, CancellationToken token = default) { - return _innerMeterAPI.Preadjustment_CompletionAsync(pp, token); + return _innerMeterAPI.Preadjustment_CompletionAsync(slot, pp, token); } - - } } \ No newline at end of file diff --git a/GenesisCordonelInterface/API/PublicModels.cs b/GenesisCordonelInterface/API/PublicModels.cs index 7de9904c7..c00540bcd 100644 --- a/GenesisCordonelInterface/API/PublicModels.cs +++ b/GenesisCordonelInterface/API/PublicModels.cs @@ -447,6 +447,42 @@ namespace GenesisCordonelInterface.API Message); } } + + public class PreadjustmentProcessResult + { + public bool Success { get; set; } + public int Slot { get; set; } + public string ProcessName { get; set; } + public string ErrorMessage { get; set; } + + /// + public override string ToString() + { + return + $"Success={Success}, " + + $"Slot={Slot}, " + + $"Process={ProcessName}, " + + $"Error={ErrorMessage ?? "None"}"; + } + } + + public class PreadjustmentDetectResult + { + public bool Success { get; set; } + public int DetectedMeterCount { get; set; } + public int DetectedThermometerCount { get; set; } + public string ErrorMessage { get; set; } + + /// + public override string ToString() + { + return + $"Success={Success}, " + + $"Meters={DetectedMeterCount}, " + + $"Thermometers={DetectedThermometerCount}, " + + $"Error={ErrorMessage ?? "None"}"; + } + } #endregion } } diff --git a/TBF/Rig/BridgeComponents/GciBridge/GciBridge.cs b/TBF/Rig/BridgeComponents/GciBridge/GciBridge.cs index cb7bd1b48..515e17ce7 100644 --- a/TBF/Rig/BridgeComponents/GciBridge/GciBridge.cs +++ b/TBF/Rig/BridgeComponents/GciBridge/GciBridge.cs @@ -18,6 +18,7 @@ using TBF.Rig.Input.DataStorage.UniDataStorageReader; using TBF.Rig.Input.DataStorage.UniDataStorageReader.Searching.Database; using Xylem.Common.Hardware.WaterMeter.WaterMeterCore; using Xylem.Common.Ui.CordonelPreadjustmentUi; +using static GenesisCordonelInterface.API.PublicModels; using static TBF.Rig.BridgeComponents.GciBridge.Interfaces.PublicModels; using GciGUIType = GenesisCordonelInterface.UI.MainView; using GciPublicModels = GenesisCordonelInterface.API.PublicModels; @@ -1425,7 +1426,7 @@ namespace TBF.Rig.BridgeComponents.GciBridge #region ================================== Preadjustment DETECT bridge ================================== - public async Task Preadjustment_DetectAsync( + public async Task Preadjustment_DetectAsync( CancellationToken token = default) { const string operation = nameof(Preadjustment_DetectAsync); @@ -1436,13 +1437,13 @@ namespace TBF.Rig.BridgeComponents.GciBridge log.InfoFormat("{0}: {1} Start.", Name, operation); - bool result = - await gciExternalInterface.Preadjustment_DetectAsync( - token) + PreadjustmentDetectResult result = + await gciExternalInterface + .Preadjustment_DetectAsync(token) .ConfigureAwait(false); log.InfoFormat( - "{0}: {1} Finish. Success={2}", + "{0}: {1} Finish. {2}", Name, operation, result); @@ -1455,15 +1456,21 @@ namespace TBF.Rig.BridgeComponents.GciBridge string.Format("{0}: {1} failed.", Name, operation), ex); - return false; + return new PreadjustmentDetectResult + { + Success = false, + ErrorMessage = ex.Message + }; } } #endregion + #region ================================== PreAdjustment PREPARATION bridge ================================== - public async Task Preadjustment_PreparationAsync( + public async Task Preadjustment_PreparationAsync( + int slot, ProcessProgress pp, CancellationToken token = default) { @@ -1476,17 +1483,22 @@ namespace TBF.Rig.BridgeComponents.GciBridge if (pp == null) throw new ArgumentNullException(nameof(pp)); - log.InfoFormat("{0}: {1} Start.", Name, operation); + log.InfoFormat( + "{0}: {1} Start. Slot={2}", + Name, + operation, + slot); - bool result = + PreadjustmentProcessResult result = await gciExternalInterface .Preadjustment_PreparationAsync( + slot, pp, token) .ConfigureAwait(false); log.InfoFormat( - "{0}: {1} Finish. Success={2}", + "{0}: {1} Finish. {2}", Name, operation, result); @@ -1499,15 +1511,23 @@ namespace TBF.Rig.BridgeComponents.GciBridge string.Format("{0}: {1} failed.", Name, operation), ex); - return false; + return new PreadjustmentProcessResult + { + Success = false, + Slot = slot, + ProcessName = "Preparation", + ErrorMessage = ex.Message + }; } } #endregion + #region ================================== PreAdjustment AMPLITUDE TEST bridge ================================== - public async Task Preadjustment_AmplitudeTestAsync( + public async Task Preadjustment_AmplitudeTestAsync( + int slot, ProcessProgress pp, CancellationToken token = default) { @@ -1520,17 +1540,22 @@ namespace TBF.Rig.BridgeComponents.GciBridge if (pp == null) throw new ArgumentNullException(nameof(pp)); - log.InfoFormat("{0}: {1} Start.", Name, operation); + log.InfoFormat( + "{0}: {1} Start. Slot={2}", + Name, + operation, + slot); - bool result = + PreadjustmentProcessResult result = await gciExternalInterface .Preadjustment_AmplitudeTestAsync( + slot, pp, token) .ConfigureAwait(false); log.InfoFormat( - "{0}: {1} Finish. Success={2}", + "{0}: {1} Finish. {2}", Name, operation, result); @@ -1543,7 +1568,13 @@ namespace TBF.Rig.BridgeComponents.GciBridge string.Format("{0}: {1} failed.", Name, operation), ex); - return false; + return new PreadjustmentProcessResult + { + Success = false, + Slot = slot, + ProcessName = "Amplitude Test", + ErrorMessage = ex.Message + }; } } @@ -1551,7 +1582,8 @@ namespace TBF.Rig.BridgeComponents.GciBridge #region ================================== PreAdjustment TEMPERATURE CALIBRATION bridge ================================== - public async Task Preadjustment_TemperatureCalibrationAsync( + public async Task Preadjustment_TemperatureCalibrationAsync( + int slot, ProcessProgress pp, CancellationToken token = default) { @@ -1564,17 +1596,22 @@ namespace TBF.Rig.BridgeComponents.GciBridge if (pp == null) throw new ArgumentNullException(nameof(pp)); - log.InfoFormat("{0}: {1} Start.", Name, operation); + log.InfoFormat( + "{0}: {1} Start. Slot={2}", + Name, + operation, + slot); - bool result = + PreadjustmentProcessResult result = await gciExternalInterface .Preadjustment_TemperatureCalibrationAsync( + slot, pp, token) .ConfigureAwait(false); log.InfoFormat( - "{0}: {1} Finish. Success={2}", + "{0}: {1} Finish. {2}", Name, operation, result); @@ -1587,15 +1624,23 @@ namespace TBF.Rig.BridgeComponents.GciBridge string.Format("{0}: {1} failed.", Name, operation), ex); - return false; + return new PreadjustmentProcessResult + { + Success = false, + Slot = slot, + ProcessName = "Temperature Calibration", + ErrorMessage = ex.Message + }; } } #endregion + #region ================================== PreAdjustment OFFSET TEST bridge ================================== - public async Task Preadjustment_OffsetTestAsync( + public async Task Preadjustment_OffsetTestAsync( + int slot, ProcessProgress pp, CancellationToken token = default) { @@ -1608,17 +1653,22 @@ namespace TBF.Rig.BridgeComponents.GciBridge if (pp == null) throw new ArgumentNullException(nameof(pp)); - log.InfoFormat("{0}: {1} Start.", Name, operation); + log.InfoFormat( + "{0}: {1} Start. Slot={2}", + Name, + operation, + slot); - bool result = + PreadjustmentProcessResult result = await gciExternalInterface .Preadjustment_OffsetTestAsync( + slot, pp, token) .ConfigureAwait(false); log.InfoFormat( - "{0}: {1} Finish. Success={2}", + "{0}: {1} Finish. {2}", Name, operation, result); @@ -1631,15 +1681,23 @@ namespace TBF.Rig.BridgeComponents.GciBridge string.Format("{0}: {1} failed.", Name, operation), ex); - return false; + return new PreadjustmentProcessResult + { + Success = false, + Slot = slot, + ProcessName = "Offset Test", + ErrorMessage = ex.Message + }; } } #endregion + #region ================================== PreAdjustment COMPLETION bridge ================================== - public async Task Preadjustment_CompletionAsync( + public async Task Preadjustment_CompletionAsync( + int slot, ProcessProgress pp, CancellationToken token = default) { @@ -1652,17 +1710,22 @@ namespace TBF.Rig.BridgeComponents.GciBridge if (pp == null) throw new ArgumentNullException(nameof(pp)); - log.InfoFormat("{0}: {1} Start.", Name, operation); + log.InfoFormat( + "{0}: {1} Start. Slot={2}", + Name, + operation, + slot); - bool result = + PreadjustmentProcessResult result = await gciExternalInterface .Preadjustment_CompletionAsync( + slot, pp, token) .ConfigureAwait(false); log.InfoFormat( - "{0}: {1} Finish. Success={2}", + "{0}: {1} Finish. {2}", Name, operation, result); @@ -1675,7 +1738,13 @@ namespace TBF.Rig.BridgeComponents.GciBridge string.Format("{0}: {1} failed.", Name, operation), ex); - return false; + return new PreadjustmentProcessResult + { + Success = false, + Slot = slot, + ProcessName = "Completion", + ErrorMessage = ex.Message + }; } } diff --git a/TBF/Rig/BridgeComponents/GciBridge/UI/Debug/MeterBatchConfigPanel.cs b/TBF/Rig/BridgeComponents/GciBridge/UI/Debug/MeterBatchConfigPanel.cs index 9d37054e2..ced0d0507 100644 --- a/TBF/Rig/BridgeComponents/GciBridge/UI/Debug/MeterBatchConfigPanel.cs +++ b/TBF/Rig/BridgeComponents/GciBridge/UI/Debug/MeterBatchConfigPanel.cs @@ -15,7 +15,7 @@ namespace TBF.Rig.BridgeComponents.GciBridge.UI.Debug private MainForm _mainform; private MainView _mainView; public Grid.MeterGridManager _gridManager; - public event Action SelectedSlotsChanged; + public event Action GetMeterRegistersClicked; private bool isRefreshing; private List comPorts = new List(); @@ -37,6 +37,9 @@ namespace TBF.Rig.BridgeComponents.GciBridge.UI.Debug _mainView._gciApi.MeterBatchStatusChanged += Api_MeterBatchStatusChanged; //global event of table + grid.CellContentClick += grid_CellContentClick; + + UpdateGrid(_api.GetMeterBatchDebugStatuses()); } @@ -276,7 +279,7 @@ namespace TBF.Rig.BridgeComponents.GciBridge.UI.Debug _api.SetSlotSelected(slot, selected); - SelectedSlotsChanged?.Invoke(); + //SelectedSlotsChanged?.Invoke(); return; } @@ -311,13 +314,14 @@ namespace TBF.Rig.BridgeComponents.GciBridge.UI.Debug if (columnName == "DetectRequest") { - await DetectRequestPortAsync(slot); + //await DetectRequestPortAsync(slot); + GetMeterRegistersClicked?.Invoke(); return; } if (columnName == "DetectStreaming") { - await DetectStreamingPortAsync(slot); + //await DetectStreamingPortAsync(slot); return; } } diff --git a/TBF/Rig/BridgeComponents/GciBridge/UI/StaraTuraAPI_GciBridge/PreadjustmentActionsView.cs b/TBF/Rig/BridgeComponents/GciBridge/UI/StaraTuraAPI_GciBridge/PreadjustmentActionsView.cs index bc3505b57..eef77cd69 100644 --- a/TBF/Rig/BridgeComponents/GciBridge/UI/StaraTuraAPI_GciBridge/PreadjustmentActionsView.cs +++ b/TBF/Rig/BridgeComponents/GciBridge/UI/StaraTuraAPI_GciBridge/PreadjustmentActionsView.cs @@ -10,6 +10,7 @@ using System.Threading.Tasks; using System.Windows.Forms; using Xylem.Common.Hardware.WaterMeter.WaterMeterCore; using Xylem.Common.Ui.CordonelPreadjustmentUi; +using static GenesisCordonelInterface.API.PublicModels; using static Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore.PreadjustmentMeter; using GciPublicModels = GenesisCordonelInterface.API.PublicModels; @@ -164,31 +165,68 @@ namespace TBF.Rig.BridgeComponents.GciBridge.UI.StaraTuraAPI_GciBridge { ExecuteAsync(async token => { - var selectedSlots = - _mainView._batchPanel.GetSelectedGridData(); - - if (!selectedSlots.Any()) - { - Log("No selected slots."); - return; - } - - var pp = CreatePreparationProgress(); - - bool success = await _bridge.Preadjustment_PreparationAsync( - pp, + await ExecutePreadjustmentForSelectedSlotsAsync( + _bridge.Preadjustment_PreparationAsync, + "Preparation", token); + }); + } - Log( - success - ? "Preparation completed." - : "Preparation failed."); + private void amplitudeTestActionButton_Click( + object sender, + EventArgs e) + { + ExecuteAsync(async token => + { + await ExecutePreadjustmentForSelectedSlotsAsync( + _bridge.Preadjustment_AmplitudeTestAsync, + "Amplitude Test", + token); + }); + } + + private void temperatureCalibrationActionButton_Click( + object sender, + EventArgs e) + { + ExecuteAsync(async token => + { + await ExecutePreadjustmentForSelectedSlotsAsync( + _bridge.Preadjustment_TemperatureCalibrationAsync, + "Temperature Calibration", + token); + }); + } + + private void offsetTestActionButton_Click( + object sender, + EventArgs e) + { + ExecuteAsync(async token => + { + await ExecutePreadjustmentForSelectedSlotsAsync( + _bridge.Preadjustment_OffsetTestAsync, + "Offset Test", + token); + }); + } + + private void completionActionButton_Click( + object sender, + EventArgs e) + { + ExecuteAsync(async token => + { + await ExecutePreadjustmentForSelectedSlotsAsync( + _bridge.Preadjustment_CompletionAsync, + "Completion", + token); }); } private void detectActionButton_Click( - object sender, - EventArgs e) + object sender, + EventArgs e) { ExecuteAsync(async token => { @@ -201,23 +239,24 @@ namespace TBF.Rig.BridgeComponents.GciBridge.UI.StaraTuraAPI_GciBridge return; } - _mainView._laatzenApi._settings = CreatePreAdjustmentSettings(selectedSlots); + _mainView._laatzenApi._settings = + CreatePreAdjustmentSettings(selectedSlots); - _mainView._laatzenApi._meterControls = CreateMeterControls(selectedSlots); + _mainView._laatzenApi._meterControls = + CreateMeterControls(selectedSlots); - bool success = await _bridge.Preadjustment_DetectAsync( - token); + PreadjustmentDetectResult result = + await _bridge.Preadjustment_DetectAsync(token); Log( - success - ? "Detect completed." - : "Detect failed."); + result.Success + ? "Detect completed. " + result + : "Detect failed. " + result); RefreshGrid(); }); } - private ProcessProgress CreatePreparationProgress() { return new ProcessProgress @@ -271,69 +310,7 @@ namespace TBF.Rig.BridgeComponents.GciBridge.UI.StaraTuraAPI_GciBridge return settings; } - private void amplitudeTestActionButton_Click(object sender, EventArgs e) - { - ExecuteAsync(async token => - { - var pp = CreatePreparationProgress(); - - bool success = await _bridge.Preadjustment_AmplitudeTestAsync(pp, token); - - Log(success - ? "Amplitude Test completed." - : "Amplitude Test failed."); - - RefreshGrid(); - }); - } - - private void temperatureCalibrationActionButton_Click(object sender, EventArgs e) - { - ExecuteAsync(async token => - { - var pp = CreatePreparationProgress(); - - bool success = await _bridge.Preadjustment_TemperatureCalibrationAsync(pp, token); - - Log(success - ? "Temperature Calibration completed." - : "Temperature Calibration failed."); - - RefreshGrid(); - }); - } - - private void offsetTestActionButton_Click(object sender, EventArgs e) - { - ExecuteAsync(async token => - { - var pp = CreatePreparationProgress(); - - bool success = await _bridge.Preadjustment_OffsetTestAsync(pp, token); - - Log(success - ? "Offset Test completed." - : "Offset Test failed."); - - RefreshGrid(); - }); - } - - private void completionActionButton_Click(object sender, EventArgs e) - { - ExecuteAsync(async token => - { - var pp = CreatePreparationProgress(); - - bool success = await _bridge.Preadjustment_CompletionAsync(pp, token); - - Log(success - ? "Completion completed." - : "Completion failed."); - - RefreshGrid(); - }); - } + private void writeRegisterButton_Click(object sender, EventArgs e) { @@ -388,5 +365,41 @@ namespace TBF.Rig.BridgeComponents.GciBridge.UI.StaraTuraAPI_GciBridge RefreshGrid(); });*/ } + + private async Task ExecutePreadjustmentForSelectedSlotsAsync( + Func> action, + string processName, + CancellationToken token) + { + var selectedSlots = + _mainView._batchPanel.GetSelectedGridData(); + + if (!selectedSlots.Any()) + { + Log(processName + ": no selected slots."); + return; + } + + var pp = + CreatePreparationProgress(); + + foreach (var selectedSlot in selectedSlots) + { + PreadjustmentProcessResult result = + await action( + selectedSlot.Slot, + pp, + token); + + Log(result.Success + ? processName + " completed. " + result + : processName + " failed. " + result); + + if (!result.Success) + break; + } + + RefreshGrid(); + } } } \ No newline at end of file diff --git a/TBF/Rig/BridgeComponents/GciBridge/UI/StaraTuraAPI_GciBridge/SlotsComPortsRegistersActionsView.cs b/TBF/Rig/BridgeComponents/GciBridge/UI/StaraTuraAPI_GciBridge/SlotsComPortsRegistersActionsView.cs index 0050571d7..142111741 100644 --- a/TBF/Rig/BridgeComponents/GciBridge/UI/StaraTuraAPI_GciBridge/SlotsComPortsRegistersActionsView.cs +++ b/TBF/Rig/BridgeComponents/GciBridge/UI/StaraTuraAPI_GciBridge/SlotsComPortsRegistersActionsView.cs @@ -36,8 +36,8 @@ namespace TBF.Rig.BridgeComponents.GciBridge.UI.StaraTuraAPI_GciBridge LoadRegisterComboBoxes(); - _mainView._batchPanel.SelectedSlotsChanged -= LoadRegisterComboBoxes; - _mainView._batchPanel.SelectedSlotsChanged += LoadRegisterComboBoxes; + _mainView._batchPanel.GetMeterRegistersClicked -= LoadRegisterComboBoxes; + _mainView._batchPanel.GetMeterRegistersClicked += LoadRegisterComboBoxes; writeRegisterNameComboBox.SelectedIndexChanged -= writeRegisterNameComboBox_SelectedIndexChanged; writeRegisterNameComboBox.SelectedIndexChanged += writeRegisterNameComboBox_SelectedIndexChanged; writeRegisterNameComboBox.TextChanged -= writeRegisterNameComboBox_SelectedIndexChanged;