diff --git a/GenesisCordonelInterface/API/Enums.cs b/GenesisCordonelInterface/API/Enums.cs new file mode 100644 index 000000000..7ac46fc4c --- /dev/null +++ b/GenesisCordonelInterface/API/Enums.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace GenesisCordonelInterface.API +{ + public class Enums + { + public enum DataStorageReaderTypes : sbyte + { + LoginPasswordsReader, + CalibrationParamsReader + } + } +} diff --git a/GenesisCordonelInterface/API/InterfaceGCIToLaatzen.cs b/GenesisCordonelInterface/API/InterfaceGCIToLaatzen.cs index 4261caae6..b4bca85a0 100644 --- a/GenesisCordonelInterface/API/InterfaceGCIToLaatzen.cs +++ b/GenesisCordonelInterface/API/InterfaceGCIToLaatzen.cs @@ -42,7 +42,6 @@ namespace GenesisCordonelInterface.API private readonly MeterBatch _meterBatch = new MeterBatch(); //Preadjustment - public PreAdjustmentSettingsContainer _settings = new PreAdjustmentSettingsContainer(); public ProcessProgress _progressProcess = new ProcessProgress(); public List _meterControls = new List(); public List _tempMeterControls = new List(); @@ -55,6 +54,11 @@ namespace GenesisCordonelInterface.API private readonly ConcurrentDictionary _selectedSlots = new ConcurrentDictionary(); + public InterfaceGCIToLaatzen() + { + + } + #endregion #region ================================== Worker ================================== @@ -1592,22 +1596,30 @@ namespace GenesisCordonelInterface.API IEnumerable selectedSlots, CancellationToken token = default) { - return Task.Run(() => Preadjustment_DetectCore(selectedSlots, token), token); + return Task.Run(() => Preadjustment_Detect(selectedSlots, token), token); + } + public PreadjustmentDetectResult PreAdjustment_DetectDirect( + IEnumerable selectedSlots, + CancellationToken token = default) + { + return Preadjustment_Detect(selectedSlots, token); } - private PreadjustmentDetectResult Preadjustment_DetectCore( + private PreadjustmentDetectResult Preadjustment_Detect( IEnumerable selectedSlots, - CancellationToken token) + CancellationToken token = default) { - const string operation = nameof(Preadjustment_DetectCore); + const string operation = nameof(Preadjustment_Detect); try { + LogInfo(operation, "Start."); + MeterBatch globalMeterBatch = new MeterBatch(); MeterBatch thermoMeterBatch = new MeterBatch(); - if (_settings == null) - throw new ArgumentNullException(nameof(_settings)); + if (_progressProcess.Setting == null) + throw new ArgumentNullException(nameof(_progressProcess.Setting)); if (_meterControls == null) throw new ArgumentNullException(nameof(_meterControls)); @@ -1624,7 +1636,7 @@ namespace GenesisCordonelInterface.API globalMeterBatch = _meterBatch; _meterControls = CreateMeterControls(selectedSlots); - if (!_settings.GetTempUseTempFlansh()) + if (!_progressProcess.Setting.GetTempUseTempFlansh()) _tempMeterControls.Clear(); var allMeterControls = new List(); @@ -1654,7 +1666,7 @@ namespace GenesisCordonelInterface.API SetUnknownStatus(allMeterControls); CheckTemperatureMeters( - _settings, + _progressProcess.Setting, _tempMeterControls, token); @@ -1684,7 +1696,6 @@ namespace GenesisCordonelInterface.API { var ctl = new MeterStateControl(slot.Slot); - ctl.SetChecked(true); ctl.IsEnabled = true; controls.Add(ctl); @@ -1818,11 +1829,16 @@ namespace GenesisCordonelInterface.API token); } + public PreAdjustmentProcessResult PreAdjustment_PreparationDirect() + { + return PreAdjustment_Preparation(); + } + /// /// Executes standalone preparation process. /// public PreAdjustmentProcessResult PreAdjustment_Preparation( - int slot) + int slot = -1) { const string operation = nameof(PreAdjustment_Preparation); @@ -1830,9 +1846,6 @@ namespace GenesisCordonelInterface.API { LogInfo(operation, $"Start. Slot={slot}"); - var meter = GetMeterThreadSafe(slot); - EnsureConnected(meter); - BaseProcess process = CreatePreparationProcess(_progressProcess); bool success = @@ -1891,6 +1904,17 @@ namespace GenesisCordonelInterface.API PreAdjustmentControl.PredefinedMessages.PreparationFailed(pp.Setting.Culture), 60); } + public bool PreAdjustment_PushCalibrationParams(double temperature) + { + if (_progressProcess != null) + { + _progressProcess.PushedTestBenchTemp = temperature; + _progressProcess.TempretureSelected = true; + return true; + } + + return false; + } #endregion @@ -1904,8 +1928,13 @@ namespace GenesisCordonelInterface.API token); } + public PreAdjustmentProcessResult PreAdjustment_AmplitudeTestDirect() + { + return PreAdjustment_AmplitudeTest(); + } + public PreAdjustmentProcessResult PreAdjustment_AmplitudeTest( - int slot) + int slot = -1) { const string operation = nameof(PreAdjustment_AmplitudeTest); @@ -1913,9 +1942,6 @@ namespace GenesisCordonelInterface.API { LogInfo(operation, $"Start. Slot={slot}"); - var meter = GetMeterThreadSafe(slot); - EnsureConnected(meter); - if (_progressProcess.Setting.TempOnly) { return new PreAdjustmentProcessResult @@ -1992,19 +2018,19 @@ namespace GenesisCordonelInterface.API token); } + public PreAdjustmentProcessResult PreAdjustment_TemperatureCalibrationDirect() + { + return PreAdjustment_TemperatureCalibration(); + } + public PreAdjustmentProcessResult PreAdjustment_TemperatureCalibration( - int slot) + int slot = -1) { const string operation = nameof(PreAdjustment_TemperatureCalibration); try { - LogInfo(operation, $"Start. Slot={slot}"); - - var meter = - GetMeterThreadSafe(slot); - - EnsureConnected(meter); + LogInfo(operation, $"Start."); BaseProcess process = CreateTemperatureCalibrationProcess(_progressProcess); @@ -2039,6 +2065,18 @@ namespace GenesisCordonelInterface.API } } + public bool PreAdjustment_PushTemperature(double temperature) + { + if (_progressProcess != null) + { + _progressProcess.PushedTestBenchTemp = temperature; + _progressProcess.TempretureSelected = true; + return true; + } + + return false; + } + /// /// Creates temperature calibration process instance based on current configuration. /// @@ -2077,8 +2115,13 @@ namespace GenesisCordonelInterface.API token); } + public PreAdjustmentProcessResult PreAdjustment_OffsetTestDirect() + { + return PreAdjustment_OffsetTest(); + } + public PreAdjustmentProcessResult PreAdjustment_OffsetTest( - int slot) + int slot = -1) { const string operation = nameof(PreAdjustment_OffsetTest); @@ -2086,10 +2129,6 @@ namespace GenesisCordonelInterface.API { LogInfo(operation, $"Start. Slot={slot}"); - var meter = GetMeterThreadSafe(slot); - - EnsureConnected(meter); - if (_progressProcess.Setting.TempOnly) { return new PreAdjustmentProcessResult @@ -2171,19 +2210,19 @@ namespace GenesisCordonelInterface.API token); } + public PreAdjustmentProcessResult PreAdjustment_CompletionDirect() + { + return PreAdjustment_Completion(); + } + public PreAdjustmentProcessResult PreAdjustment_Completion( - int slot) + int slot = -1) { const string operation = nameof(PreAdjustment_Completion); try { - LogInfo(operation, $"Start. Slot={slot}"); - - var meter = - GetMeterThreadSafe(slot); - - EnsureConnected(meter); + LogInfo(operation, $"Start."); BaseProcess process = CreateCompletionProcess(_progressProcess); diff --git a/GenesisCordonelInterface/API/InterfaceOutsideToGCI.cs b/GenesisCordonelInterface/API/InterfaceOutsideToGCI.cs index 35e8033b7..e6c0726c1 100644 --- a/GenesisCordonelInterface/API/InterfaceOutsideToGCI.cs +++ b/GenesisCordonelInterface/API/InterfaceOutsideToGCI.cs @@ -1,11 +1,16 @@ using CordonelPreadjustmentUi; using CordonelPreadjustmentUi.Processes.Itinerary; +using GenesisCordonelInterface.Core.DataStorage.Config; +using GenesisCordonelInterface.Core.DataStorage.Reading.Common.Models; +using GenesisCordonelInterface.Core.DataStorage.Reading.Implementation.MeterLoginPasswords; +using GenesisCordonelInterface.Core.DataStorage.Reading.Implementation.PreAdjustmentCalibrationParams; 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.Logic.ProductionOrderCore.OrderData; using Xylem.Common.Ui.CordonelPreadjustmentUi; using static GenesisCordonelInterface.API.PublicModels; @@ -35,13 +40,55 @@ namespace GenesisCordonelInterface.API /// Occurs when meter batch status information changes. /// public event Action> MeterBatchStatusChanged; + private readonly IMeterLoginPasswordReader loginPasswordsReader; + private readonly IPreAdjustmentCalibrationParamsReader calibrationParamsReader; /// /// Initializes a new instance of the public GCI facade. /// public InterfaceOutsideToGCI() { - _innerMeterAPI = new InterfaceGCIToLaatzen(); + + } + + /// + /// Initializes a new instance of the public GCI facade. + /// + public InterfaceOutsideToGCI( + InterfaceGCIToLaatzen innerMeterApi, + IMeterLoginPasswordReader passwordReader, + IPreAdjustmentCalibrationParamsReader calibrationReader) + { + _innerMeterAPI = innerMeterApi?? throw new ArgumentNullException(nameof(innerMeterApi)); + loginPasswordsReader = passwordReader ?? throw new ArgumentNullException(nameof(passwordReader)); + calibrationParamsReader = calibrationReader ?? throw new ArgumentNullException(nameof(calibrationReader)); + + //init handlers + //_innerMeterAPI._progressProcess.OnRequestedCalibrationParamsFromDb += RequestedCalibrationParamsFromDb; + } + + private async void RequestedCalibrationParamsFromDb( + object sender, + EventArgsProcessProgress e) + { + try + { + DataQuery query = new DataQuery(); + query.QueryParams.Add(((int)e.Value.Setting.MeterSize).ToString()); + + Dictionary calibrationParams = await ReadPreAdjustmentCalibrationParamsAsync(query).ConfigureAwait(false); + + e.Value.PushedCalibrationParams = calibrationParams; + } + catch (Exception ex) + { + e.Value.DebugMessage( + $"Calibration params reading failed: {ex.Message}"); + } + finally + { + e.Value.CalibrationParamsReadEvent.Set(); + } } // Laatzen ToolBox actions @@ -50,7 +97,7 @@ namespace GenesisCordonelInterface.API public PortDetectionResult DetectStreamingPort(int slot) { - var result = _innerMeterAPI.DetectStreamingPort(slot); + var result = _innerMeterAPI?.DetectStreamingPort(slot); //RaiseMeterBatchStatusChanged(); return result; } @@ -59,14 +106,14 @@ namespace GenesisCordonelInterface.API int slot, CancellationToken token = default(CancellationToken)) { - var result = await _innerMeterAPI.DetectStreamingPortAsync(slot, token); + var result = await _innerMeterAPI?.DetectStreamingPortAsync(slot, token); //RaiseMeterBatchStatusChanged(); return result; } public PortDetectionResult DetectRequestPort(int slot) { - var result = _innerMeterAPI.DetectRequestPort(slot); + var result = _innerMeterAPI?.DetectRequestPort(slot); //RaiseMeterBatchStatusChanged(); return result; } @@ -75,7 +122,7 @@ namespace GenesisCordonelInterface.API int slot, CancellationToken token = default(CancellationToken)) { - var result = await _innerMeterAPI.DetectRequestPortAsync(slot, token); + var result = await _innerMeterAPI?.DetectRequestPortAsync(slot, token); //RaiseMeterBatchStatusChanged(); return result; } @@ -484,6 +531,7 @@ namespace GenesisCordonelInterface.API return result; } + #endregion #region ================================== DEBUG STATUS ================================== @@ -497,7 +545,7 @@ namespace GenesisCordonelInterface.API /// public List GetWorkerDebugStatuses() { - return _innerMeterAPI.GetWorkerDebugStatuses(); + return _innerMeterAPI?.GetWorkerDebugStatuses(); } /// @@ -509,7 +557,7 @@ namespace GenesisCordonelInterface.API /// public List GetMeterBatchDebugStatuses() { - return _innerMeterAPI.GetMeterBatchDebugStatuses(); + return _innerMeterAPI?.GetMeterBatchDebugStatuses(); } /// @@ -538,7 +586,7 @@ namespace GenesisCordonelInterface.API /// Selection state. public void SetSlotSelected(int slot, bool selected) { - _innerMeterAPI.SetSlotSelected(slot, selected); + _innerMeterAPI?.SetSlotSelected(slot, selected); RaiseMeterBatchStatusChanged(); } @@ -551,7 +599,7 @@ namespace GenesisCordonelInterface.API /// public bool IsSlotSelected(int slot) { - return _innerMeterAPI.IsSlotSelected(slot); + return (bool)(_innerMeterAPI?.IsSlotSelected(slot)); } /// @@ -562,7 +610,7 @@ namespace GenesisCordonelInterface.API /// public List GetSelectedSlots() { - return _innerMeterAPI.GetSelectedSlots(); + return _innerMeterAPI?.GetSelectedSlots(); } #endregion @@ -577,7 +625,7 @@ namespace GenesisCordonelInterface.API /// public List GetAllRegisterNames() { - return _innerMeterAPI.GetAllRegisterNames(); + return _innerMeterAPI?.GetAllRegisterNames(); } #endregion @@ -589,7 +637,10 @@ namespace GenesisCordonelInterface.API ProcessProgress pp, List mc) { - return _innerMeterAPI.Preadjustment_Initialization(pp, mc); + //init handlers + pp.OnRequestedCalibrationParamsFromDb += RequestedCalibrationParamsFromDb; + + return _innerMeterAPI?.Preadjustment_Initialization(pp, mc); } public Task PreAdjustment_DetectAsync( @@ -599,6 +650,13 @@ namespace GenesisCordonelInterface.API return _innerMeterAPI.PreAdjustment_DetectAsync(selectedSlots, token); } + public PreadjustmentDetectResult PreAdjustment_DetectDirect( + IEnumerable selectedSlots, + CancellationToken token = default) + { + return _innerMeterAPI.PreAdjustment_DetectDirect(selectedSlots, token); + } + public Task PreAdjustment_PreparationAsync( int slot, CancellationToken token = default) @@ -606,6 +664,11 @@ namespace GenesisCordonelInterface.API return _innerMeterAPI.PreAdjustment_PreparationAsync(slot, token); } + public PreAdjustmentProcessResult PreAdjustment_PreparationDirect() + { + return _innerMeterAPI.PreAdjustment_PreparationDirect(); + } + public Task PreAdjustment_AmplitudeTestAsync( int slot, CancellationToken token = default) @@ -613,6 +676,11 @@ namespace GenesisCordonelInterface.API return _innerMeterAPI.PreAdjustment_AmplitudeTestAsync(slot, token); } + public PreAdjustmentProcessResult PreAdjustment_AmplitudeTestDirect() + { + return _innerMeterAPI.PreAdjustment_AmplitudeTestDirect(); + } + public Task PreAdjustment_TemperatureCalibrationAsync( int slot, CancellationToken token = default) @@ -620,6 +688,17 @@ namespace GenesisCordonelInterface.API return _innerMeterAPI.PreAdjustment_TemperatureCalibrationAsync(slot, token); } + public PreAdjustmentProcessResult PreAdjustment_TemperatureCalibrationDirect() + { + return _innerMeterAPI.PreAdjustment_TemperatureCalibrationDirect(); + } + + public bool PreAdjustment_PushTemperature( + double temperature) + { + return _innerMeterAPI.PreAdjustment_PushTemperature(temperature); + } + public Task PreAdjustment_OffsetTestAsync( int slot, CancellationToken token = default) @@ -627,6 +706,11 @@ namespace GenesisCordonelInterface.API return _innerMeterAPI.PreAdjustment_OffsetTestAsync(slot, token); } + public PreAdjustmentProcessResult PreAdjustment_OffsetTestDirect() + { + return _innerMeterAPI.PreAdjustment_OffsetTestDirect(); + } + public Task PreAdjustment_CompletionAsync( int slot, CancellationToken token = default) @@ -634,6 +718,68 @@ namespace GenesisCordonelInterface.API return _innerMeterAPI.PreAdjustment_CompletionAsync(slot, token); } + public PreAdjustmentProcessResult PreAdjustment_CompletionDirect() + { + return _innerMeterAPI.PreAdjustment_CompletionDirect(); + } + + #endregion + + #region ================================== UNI DATA STORAGE READER ================================== + + //LoginPasswords reading + + /// + /// Reads meter login password from configured GCI data storage. + /// + /// + /// Data query containing PCB ID or another configured lookup value. + /// + /// + /// Cancellation token used to cancel the asynchronous operation. + /// + /// + /// Password if found; otherwise null. + /// + public Task ReadMeterLoginPasswordAsync( + DataQuery query, + CancellationToken token = default) + { + return loginPasswordsReader.ReadMeterLoginPasswordAsync( + query, + token); + } + + //CalibrationParams reading + + /// + /// Reads pre-adjustment calibration parameters + /// from configured GCI data storage. + /// + /// + /// Data query containing meter size or another configured lookup value. + /// + /// + /// Cancellation token used to cancel the asynchronous operation. + /// + /// + /// Dictionary: + /// + /// Key: + /// Calibration parameter name + /// + /// Value: + /// Calibration parameter value + /// + public Task> ReadPreAdjustmentCalibrationParamsAsync( + DataQuery query, + CancellationToken token = default) + { + return calibrationParamsReader.ReadCalibrationParamsAsync( + query, + token); + } + #endregion } } \ No newline at end of file diff --git a/GenesisCordonelInterface/Config/gci_config.json b/GenesisCordonelInterface/Config/gci_config.json index 617517733..f4c43ac1f 100644 --- a/GenesisCordonelInterface/Config/gci_config.json +++ b/GenesisCordonelInterface/Config/gci_config.json @@ -21,15 +21,16 @@ "PreAdjustmentCalibrationParams": { "___Documentation___": { - "Description": "Reads pre-adjustment values from CSV", - "DataSource": "Relative path resolved from application directory", - "QueryTemplate": "CSV/JSON syntax: SELECT [ReturnColumn] WHERE [MatchColumn]=QUERYPARAM or SELECT COLUMN(1) WHERE COLUMN(0)=QUERYPARAM" + "Description": "Reads pre-adjustment calibration parameters by meter size", + "Type": "Supported: LocalDatabase, RemoteDatabase, LocalCsv, LocalJson, RestApi", + "DataSource": "Database connection string", + "QueryTemplate": "QUERYPARAM is placeholder for runtime value. Example: WHERE [MeterSize]=QUERYPARAM -> meter size provided during ReadCalibrationParamsAsync()." }, "Name": "PreAdjustmentCalibrationParams", - "Type": "LocalCsv", - "DataSource": "Data\\preadjustment_params.csv", - "QueryTemplate": "SELECT [Offset] WHERE [PcbId] = QUERYPARAM" + "Type": "LocalDatabase", + "DataSource": "Server=(localdb)\\MojaDB;Database=UnionTownCalibAndSkeleton;Integrated Security=True;", + "QueryTemplate": "SELECT [ParameterName], [ParameterValue] FROM [dbo].[PreAdjustmentCalibrationParams] WHERE [MeterSize] = QUERYPARAM" } } } diff --git a/GenesisCordonelInterface/Core/Config/GciConfig.cs b/GenesisCordonelInterface/Core/Config/GciConfig.cs new file mode 100644 index 000000000..b97a8c7c8 --- /dev/null +++ b/GenesisCordonelInterface/Core/Config/GciConfig.cs @@ -0,0 +1,32 @@ +namespace GenesisCordonelInterface.Core.Config +{ + /// + /// Root GCI configuration object loaded from gci_config.json. + /// + /// This class represents the top-level configuration structure + /// and serves as an entry point for all configurable GCI features. + /// + /// Example: + /// + /// { + /// "DataStorageSection": + /// { + /// ... + /// } + /// } + /// + public class GciConfig + { + /// + /// Data storage configuration section. + /// + /// Contains definitions for all configured readers and writers, + /// such as: + /// + /// - MeterLoginPasswords + /// - PreAdjustmentCalibrationParams + /// - future storage providers + /// + public DataStorage.Config.GciDataStorageConfig DataStorageSection { get; set; } + } +} \ No newline at end of file diff --git a/GenesisCordonelInterface/Core/Config/GciConfigLoader.cs b/GenesisCordonelInterface/Core/Config/GciConfigLoader.cs new file mode 100644 index 000000000..78b635f81 --- /dev/null +++ b/GenesisCordonelInterface/Core/Config/GciConfigLoader.cs @@ -0,0 +1,177 @@ +using System; +using System.IO; +using GenesisCordonelInterface.Core.DataStorage.Reading.Common; +using GenesisCordonelInterface.Core.DataStorage.Reading.Common.Models; +using Newtonsoft.Json; + +namespace GenesisCordonelInterface.Core.Config +{ + /// + /// Loads GCI configuration from gci_config.json. + /// + /// Responsibilities: + /// - Locate configuration file + /// - Deserialize JSON into strongly typed objects + /// - Normalize relative file paths + /// - Preserve database connection strings and REST URLs + /// + /// Example: + /// + /// Config/ + /// gci_config.json + /// + /// Data/ + /// meter_passwords.csv + /// + /// Relative paths: + /// Data\file.csv + /// + /// become: + /// + /// C:\App\bin\Debug\Data\file.csv + /// + /// Database sources remain unchanged: + /// + /// Server=(localdb)\MojaDB;Database=... + /// + public static class GciConfigLoader + { + /// + /// Loads default GCI configuration from: + /// + /// Config\gci_config.json + /// + /// + /// Loaded GCI configuration. + /// + public static GciConfig LoadDefault() + { + string baseDirectory = AppDomain.CurrentDomain.BaseDirectory; + + string configPath = Path.Combine( + baseDirectory, + "Config", + "gci_config.json"); + + return Load(configPath, baseDirectory); + } + + /// + /// Loads GCI configuration from specified file. + /// + /// + /// Path to configuration json file. + /// + /// + /// Base directory used for resolving relative paths. + /// + /// + /// Loaded configuration object. + /// + public static GciConfig Load( + string configPath, + string baseDirectory = null) + { + if (string.IsNullOrWhiteSpace(configPath)) + throw new ArgumentException( + "Config path must not be empty.", + nameof(configPath)); + + if (!File.Exists(configPath)) + throw new FileNotFoundException( + "GCI config file was not found.", + configPath); + + string json = File.ReadAllText(configPath); + + GciConfig config = + JsonConvert.DeserializeObject(json); + + if (config == null) + throw new InvalidOperationException( + "GCI config could not be loaded."); + + NormalizeDataStoragePaths( + config, + baseDirectory ?? Path.GetDirectoryName(configPath)); + + return config; + } + + /// + /// Normalizes paths for all configured data storage entries. + /// + /// Converts relative file paths into absolute paths. + /// Database connection strings remain untouched. + /// + /// + /// Loaded configuration object. + /// + /// + /// Base path used for relative resolution. + /// + private static void NormalizeDataStoragePaths( + GciConfig config, + string baseDirectory) + { + if (config.DataStorageSection == null) + return; + + NormalizePath( + config.DataStorageSection.MeterLoginPasswords, + baseDirectory); + + NormalizePath( + config.DataStorageSection.PreAdjustmentCalibrationParams, + baseDirectory); + } + + /// + /// Converts relative file paths into absolute paths. + /// + /// Applies only to: + /// - LocalCsv + /// - RemoteCsv + /// - LocalJson + /// - RemoteJson + /// + /// Does not modify: + /// - Database connection strings + /// - REST URLs + /// + /// + /// Storage configuration. + /// + /// + /// Base path for resolution. + /// + private static void NormalizePath( + DataStorageConfig storageConfig, + string baseDirectory) + { + if (storageConfig == null) + return; + + if (string.IsNullOrWhiteSpace(storageConfig.DataSource)) + return; + + // Database connection strings and URLs + // must never be treated as file paths. + if (storageConfig.Type == DataStorageType.LocalDatabase || + storageConfig.Type == DataStorageType.RemoteDatabase || + storageConfig.Type == DataStorageType.RestApi) + { + return; + } + + if (Path.IsPathRooted(storageConfig.DataSource)) + return; + + storageConfig.DataSource = + Path.GetFullPath( + Path.Combine( + baseDirectory, + storageConfig.DataSource)); + } + } +} \ No newline at end of file diff --git a/GenesisCordonelInterface/Core/Config/gci_config.json b/GenesisCordonelInterface/Core/Config/gci_config.json new file mode 100644 index 000000000..0a25a6d34 --- /dev/null +++ b/GenesisCordonelInterface/Core/Config/gci_config.json @@ -0,0 +1,36 @@ +{ + "_Comment": "GCI DataStorage configuration", + + "DataStorageSection": { + + "MeterLoginPasswords": { + + "___Documentation___": { + "Description": "Reads login passwords for meters by PCB ID", + "Type": "Supported: LocalDatabase, RemoteDatabase, LocalCsv, LocalJson, RestApi", + "DataSource": "Database connection string", + "QueryTemplate": "QUERYPARAM is placeholder for runtime value. Example: WHERE [PcbId]=QUERYPARAM -> PCB ID provided during GetPasswordAsync()." + }, + + "Name": "MeterLoginPasswords", + "Type": "LocalDatabase", + "DataSource": "Server=(localdb)\\SensusLocalDB;Database=UnionTownCalibAndSkeleton;Integrated Security=True;", + "QueryTemplate": "SELECT [Password] FROM [dbo].[SkeletonKeys] WHERE [PcbId] = QUERYPARAM" + }, + + "PreAdjustmentCalibrationParams": { + + "___Documentation___": { + "Description": "Reads pre-adjustment calibration parameters by meter size", + "Type": "Supported: LocalDatabase, RemoteDatabase, LocalCsv, LocalJson, RestApi", + "DataSource": "Database connection string", + "QueryTemplate": "QUERYPARAM is placeholder for runtime value. Example: WHERE [MeterSize]=QUERYPARAM -> meter size provided during ReadCalibrationParamsAsync()." + }, + + "Name": "PreAdjustmentCalibrationParams", + "Type": "LocalDatabase", + "DataSource": "Server=(localdb)\\SensusLocalDB;Database=UnionTownCalibAndSkeleton;Integrated Security=True;", + "QueryTemplate": "SELECT [ParameterName], [ParameterValue] FROM [dbo].[PreAdjustmentCalibrationParams] WHERE [MeterSize] = QUERYPARAM" + } + } +} diff --git a/GenesisCordonelInterface/Core/DataStorage/Reading/Common/Models/DataStorageConfig.cs b/GenesisCordonelInterface/Core/DataStorage/Reading/Common/Models/DataStorageConfig.cs index 2bc89bc64..16b68b17e 100644 --- a/GenesisCordonelInterface/Core/DataStorage/Reading/Common/Models/DataStorageConfig.cs +++ b/GenesisCordonelInterface/Core/DataStorage/Reading/Common/Models/DataStorageConfig.cs @@ -46,5 +46,17 @@ namespace GenesisCordonelInterface.Core.DataStorage.Reading.Common.Models /// WHERE [PcbId]=QUERYPARAM /// public string QueryTemplate { get; set; } + + public DataStorageConfig( + string name, + DataStorageType type, + string dataSource, + string queryTemplate) + { + Name = name; + Type = type; + DataSource = dataSource; + QueryTemplate = queryTemplate; + } } } diff --git a/GenesisCordonelInterface/Core/DataStorage/Reading/Common/Models/DatabaseSearchResult.cs b/GenesisCordonelInterface/Core/DataStorage/Reading/Common/Models/DatabaseSearchResult.cs index 2f69501ee..b52f2186b 100644 --- a/GenesisCordonelInterface/Core/DataStorage/Reading/Common/Models/DatabaseSearchResult.cs +++ b/GenesisCordonelInterface/Core/DataStorage/Reading/Common/Models/DatabaseSearchResult.cs @@ -2,17 +2,52 @@ namespace GenesisCordonelInterface.Core.DataStorage.Reading.Common.Models { - public class DatabaseSearchResult + /// + /// Represents result returned by database-based + /// data storage readers. + /// + /// Supports both: + /// + /// - Single-row lookups + /// (e.g. MeterLoginPasswords) + /// + /// - Multi-row queries + /// (e.g. PreAdjustmentCalibrationParams) + /// + internal class DatabaseSearchResult { + /// + /// Indicates whether at least one record + /// was found. + /// public bool Found { get; set; } + /// + /// Executed SQL query text. + /// Mainly intended for diagnostics + /// and troubleshooting. + /// public string Query { get; set; } - public Dictionary Values { get; set; } + /// + /// First returned row represented as + /// column/value pairs. + /// + /// Preserved for backward compatibility + /// with existing readers expecting + /// a single database record. + /// + public Dictionary Values { get; } + = new Dictionary(); - public DatabaseSearchResult() - { - Values = new Dictionary(); - } + /// + /// All returned rows represented as + /// a collection of column/value dictionaries. + /// + /// Intended for queries returning + /// multiple records. + /// + public List> Rows { get; } + = new List>(); } } \ No newline at end of file diff --git a/GenesisCordonelInterface/Core/DataStorage/Reading/Common/Providers/DatabaseDataStorageReader.cs b/GenesisCordonelInterface/Core/DataStorage/Reading/Common/Providers/DatabaseDataStorageReader.cs index acf2ccee3..e313f76ec 100644 --- a/GenesisCordonelInterface/Core/DataStorage/Reading/Common/Providers/DatabaseDataStorageReader.cs +++ b/GenesisCordonelInterface/Core/DataStorage/Reading/Common/Providers/DatabaseDataStorageReader.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Data; using System.Data.SqlClient; using GenesisCordonelInterface.Core.DataStorage.Reading.Common.Models; @@ -14,76 +15,152 @@ namespace GenesisCordonelInterface.Core.DataStorage.Reading.Common.Providers /// QueryTemplate must contain QUERYPARAM placeholder. /// /// Example: - /// SELECT [Password] FROM [dbo].[SkeletonKeys] WHERE [PcbId] = QUERYPARAM /// - /// The placeholder is internally converted to SQL parameter @value. + /// SELECT [Password] + /// FROM [dbo].[SkeletonKeys] + /// WHERE [PcbId] = QUERYPARAM + /// + /// or + /// + /// SELECT [ParameterName], [ParameterValue] + /// FROM [dbo].[PreAdjustmentCalibrationParams] + /// WHERE [Dn_InternalId] = QUERYPARAM + /// + /// The placeholder is internally converted + /// to SQL parameter @value. + /// + /// Supports both: + /// + /// - Single-row lookups + /// - Multi-row result sets /// public class DatabaseDataStorageReader : IDataStorageReader { /// - /// Data storage configuration containing connection string and query template. + /// Data storage configuration containing + /// connection string and query template. /// private readonly DataStorageConfig config; /// - /// Creates SQL Server data storage reader using provided configuration. + /// Creates SQL Server data storage reader + /// using provided configuration. /// /// - /// Data storage configuration loaded from gci_config.json. + /// Data storage configuration loaded + /// from gci_config.json. /// - public DatabaseDataStorageReader(DataStorageConfig config) + public DatabaseDataStorageReader( + DataStorageConfig config) { - this.config = config ?? throw new ArgumentNullException(nameof(config)); + this.config = + config ?? throw new ArgumentNullException(nameof(config)); } /// - /// Executes configured SQL query and returns first matching row. + /// Executes configured SQL query and returns + /// matching database records. + /// + /// Single-row queries populate: + /// DatabaseSearchResult.Values + /// + /// Multi-row queries populate: + /// DatabaseSearchResult.Rows + /// + /// For backward compatibility, the first row + /// is also stored in Values. /// /// /// Query object containing lookup parameter. /// /// - /// DatabaseSearchResult containing returned SQL columns and values. + /// DatabaseSearchResult containing returned + /// database records. + /// + /// Values contains the first returned row. + /// + /// Rows contains the complete result set. /// public object GetData(DataQuery query) { if (query == null) throw new ArgumentNullException(nameof(query)); - ReaderDiagnosticResult sourceResult = TestSource(true); + ReaderDiagnosticResult sourceResult = + TestSource(true); + if (!sourceResult.Success) throw new InvalidOperationException(sourceResult.Message); - string sqlText = PrepareSqlText(config.QueryTemplate); - object queryValue = ExtractQueryValue(query); + string sqlText = + PrepareSqlText(config.QueryTemplate); - using (SqlConnection connection = new SqlConnection(config.DataSource)) - using (SqlCommand command = new SqlCommand(sqlText, connection)) + object queryValue = + ExtractQueryValue(query); + + using (SqlConnection connection = + new SqlConnection(config.DataSource)) + + using (SqlCommand command = + new SqlCommand(sqlText, connection)) { AddQueryParameter(command, queryValue); connection.Open(); - using (SqlDataReader reader = command.ExecuteReader(CommandBehavior.SingleRow)) + // Full result set is required because some + // storage definitions return multiple records + // (e.g. PreAdjustmentCalibrationParams). + using (SqlDataReader reader = + command.ExecuteReader()) { - DatabaseSearchResult result = new DatabaseSearchResult - { - Query = sqlText - }; + DatabaseSearchResult result = + new DatabaseSearchResult + { + Query = sqlText + }; - if (!reader.Read()) + while (reader.Read()) { - result.Found = false; - return result; + result.Found = true; + + // Represents one database row. + Dictionary row = + new Dictionary(); + + for (int i = 0; i < reader.FieldCount; i++) + { + object value = + reader.GetValue(i); + + object normalizedValue = + value == DBNull.Value + ? null + : value; + + row[reader.GetName(i)] = + normalizedValue; + } + + // Preserve first row for legacy consumers + // expecting a single returned database record + // (e.g. MeterLoginPasswordReader). + if (result.Rows.Count == 0) + { + foreach (var item in row) + { + result.Values[item.Key] = + item.Value; + } + } + + // Store complete database result set. + result.Rows.Add(row); } - result.Found = true; - - for (int i = 0; i < reader.FieldCount; i++) + if (result.Rows.Count == 0) { - object value = reader.GetValue(i); - result.Values[reader.GetName(i)] = - value == DBNull.Value ? null : value; + result.Found = false; } return result; @@ -92,7 +169,8 @@ namespace GenesisCordonelInterface.Core.DataStorage.Reading.Common.Providers } /// - /// Tests whether SQL Server connection can be opened. + /// Tests whether SQL Server connection + /// can be opened. /// /// /// Enables detailed diagnostic output. @@ -100,45 +178,70 @@ namespace GenesisCordonelInterface.Core.DataStorage.Reading.Common.Providers /// /// Diagnostic result of SQL connection test. /// - public ReaderDiagnosticResult TestSource(bool enableDiagnostics) + public ReaderDiagnosticResult TestSource( + bool enableDiagnostics) { - ReaderDiagnosticResult result = new ReaderDiagnosticResult(); + ReaderDiagnosticResult result = + new ReaderDiagnosticResult(); try { if (string.IsNullOrWhiteSpace(config.DataSource)) - throw new InvalidOperationException("Data source is empty."); + { + throw new InvalidOperationException( + "Data source is empty."); + } - Log(result, enableDiagnostics, "Opening SQL connection."); + Log( + result, + enableDiagnostics, + "Opening SQL connection."); - using (SqlConnection connection = new SqlConnection(config.DataSource)) + using (SqlConnection connection = + new SqlConnection(config.DataSource)) { connection.Open(); - Log(result, enableDiagnostics, "Connection opened successfully."); + Log( + result, + enableDiagnostics, + "Connection opened successfully."); - using (SqlCommand command = new SqlCommand("SELECT 1", connection)) + using (SqlCommand command = + new SqlCommand("SELECT 1", connection)) { - object value = command.ExecuteScalar(); - Log(result, enableDiagnostics, "Test query result: " + value); + object value = + command.ExecuteScalar(); + + Log( + result, + enableDiagnostics, + "Test query result: " + value); } } result.Success = true; - result.Message = "Connection to SQL Server OK."; + result.Message = + "Connection to SQL Server OK."; } catch (Exception ex) { result.Success = false; - result.Message = "Failed to connect to SQL Server. " + ex.Message; - Log(result, enableDiagnostics, ex.ToString()); + result.Message = + "Failed to connect to SQL Server. " + ex.Message; + + Log( + result, + enableDiagnostics, + ex.ToString()); } return result; } /// - /// Tests whether configured SQL query can be prepared and executed. + /// Tests whether configured SQL query + /// can be prepared and executed. /// /// /// Enables detailed diagnostic output. @@ -146,16 +249,22 @@ namespace GenesisCordonelInterface.Core.DataStorage.Reading.Common.Providers /// /// Diagnostic result of query execution test. /// - public ReaderDiagnosticResult TestQuery(bool enableDiagnostics) + public ReaderDiagnosticResult TestQuery( + bool enableDiagnostics) { - ReaderDiagnosticResult result = new ReaderDiagnosticResult(); + ReaderDiagnosticResult result = + new ReaderDiagnosticResult(); try { if (string.IsNullOrWhiteSpace(config.QueryTemplate)) - throw new InvalidOperationException("Query template is empty."); + { + throw new InvalidOperationException( + "Query template is empty."); + } - string sqlText = PrepareSqlText(config.QueryTemplate); + string sqlText = + PrepareSqlText(config.QueryTemplate); Log(result, enableDiagnostics, "Original template:"); Log(result, enableDiagnostics, config.QueryTemplate); @@ -163,69 +272,91 @@ namespace GenesisCordonelInterface.Core.DataStorage.Reading.Common.Providers Log(result, enableDiagnostics, "Prepared SQL:"); Log(result, enableDiagnostics, sqlText); - using (SqlConnection connection = new SqlConnection(config.DataSource)) - using (SqlCommand command = new SqlCommand(sqlText, connection)) + using (SqlConnection connection = + new SqlConnection(config.DataSource)) + + using (SqlCommand command = + new SqlCommand(sqlText, connection)) { AddQueryParameter(command, "TEST"); connection.Open(); - object value = command.ExecuteScalar(); + + object value = + command.ExecuteScalar(); result.Data = value; - Log(result, enableDiagnostics, "Query executed successfully."); + Log( + result, + enableDiagnostics, + "Query executed successfully."); } result.Success = true; - result.Message = "Query executed successfully."; + result.Message = + "Query executed successfully."; } catch (Exception ex) { result.Success = false; - result.Message = "Query execution failed. " + ex.Message; - Log(result, enableDiagnostics, ex.ToString()); + result.Message = + "Query execution failed. " + ex.Message; + + Log( + result, + enableDiagnostics, + ex.ToString()); } return result; } /// - /// Converts configured QueryTemplate to executable SQL text. + /// Converts configured QueryTemplate + /// to executable SQL text. /// /// - /// SQL query template containing QUERYPARAM placeholder. + /// SQL query template containing + /// QUERYPARAM placeholder. /// /// - /// SQL text with QUERYPARAM replaced by @value parameter. + /// SQL text with QUERYPARAM replaced + /// by @value parameter. /// - private static string PrepareSqlText(string queryTemplate) + private static string PrepareSqlText( + string queryTemplate) { if (string.IsNullOrWhiteSpace(queryTemplate)) + { throw new ArgumentException( "Query template must not be empty.", nameof(queryTemplate)); + } if (!queryTemplate.Contains("QUERYPARAM")) + { throw new InvalidOperationException( "Query template must contain QUERYPARAM placeholder."); + } - return queryTemplate.Replace("QUERYPARAM", "@value"); + return queryTemplate.Replace( + "QUERYPARAM", + "@value"); } /// /// Extracts first query parameter value. /// - /// - /// Data query containing query parameters. - /// - /// - /// First query parameter value. - /// - private static object ExtractQueryValue(DataQuery query) + private static object ExtractQueryValue( + DataQuery query) { - if (query.QueryParams == null || query.QueryParams.Count == 0) + if (query.QueryParams == null || + query.QueryParams.Count == 0) + { throw new InvalidOperationException( "DataQuery does not contain any query parameter."); + } return query.QueryParams[0]; } @@ -233,32 +364,25 @@ namespace GenesisCordonelInterface.Core.DataStorage.Reading.Common.Providers /// /// Adds lookup parameter to SQL command. /// - /// - /// SQL command. - /// - /// - /// Query parameter value. - /// - private static void AddQueryParameter(SqlCommand command, object value) + private static void AddQueryParameter( + SqlCommand command, + object value) { command.Parameters.Clear(); - SqlParameter parameter = command.Parameters.Add("@value", SqlDbType.Variant); - parameter.Value = value ?? DBNull.Value; + SqlParameter parameter = + command.Parameters.Add( + "@value", + SqlDbType.Variant); + + parameter.Value = + value ?? DBNull.Value; } /// - /// Adds diagnostic line when diagnostics are enabled. + /// Adds diagnostic line when diagnostics + /// are enabled. /// - /// - /// Diagnostic result object. - /// - /// - /// Indicates whether diagnostics are enabled. - /// - /// - /// Diagnostic message. - /// private static void Log( ReaderDiagnosticResult result, bool enableDiagnostics, diff --git a/GenesisCordonelInterface/Core/DataStorage/Reading/Implementation/MeterLoginPasswords/IMeterLoginPasswordReader.cs b/GenesisCordonelInterface/Core/DataStorage/Reading/Implementation/MeterLoginPasswords/IMeterLoginPasswordReader.cs index 28baa793b..1d52ea09d 100644 --- a/GenesisCordonelInterface/Core/DataStorage/Reading/Implementation/MeterLoginPasswords/IMeterLoginPasswordReader.cs +++ b/GenesisCordonelInterface/Core/DataStorage/Reading/Implementation/MeterLoginPasswords/IMeterLoginPasswordReader.cs @@ -1,4 +1,5 @@ -using System.Threading; +using GenesisCordonelInterface.Core.DataStorage.Reading.Common.Models; +using System.Threading; using System.Threading.Tasks; namespace GenesisCordonelInterface.Core.DataStorage.Reading.Implementation.MeterLoginPasswords @@ -27,7 +28,7 @@ namespace GenesisCordonelInterface.Core.DataStorage.Reading.Implementation.Meter /// /// Password if found; otherwise null. /// - string GetPassword(string queryParam); + string GetPassword(DataQuery query); /// /// Reads meter login password asynchronously. @@ -43,8 +44,8 @@ namespace GenesisCordonelInterface.Core.DataStorage.Reading.Implementation.Meter /// /// Password if found; otherwise null. /// - Task GetPasswordAsync( - string queryParam, + Task ReadMeterLoginPasswordAsync( + DataQuery query, CancellationToken token = default); } } \ No newline at end of file diff --git a/GenesisCordonelInterface/Core/DataStorage/Reading/Implementation/MeterLoginPasswords/MeterLoginPasswordReader.cs b/GenesisCordonelInterface/Core/DataStorage/Reading/Implementation/MeterLoginPasswords/MeterLoginPasswordReader.cs index 2a7943b8f..e34b07580 100644 --- a/GenesisCordonelInterface/Core/DataStorage/Reading/Implementation/MeterLoginPasswords/MeterLoginPasswordReader.cs +++ b/GenesisCordonelInterface/Core/DataStorage/Reading/Implementation/MeterLoginPasswords/MeterLoginPasswordReader.cs @@ -7,85 +7,120 @@ using System.Reflection; using System.Threading; using System.Threading.Tasks; -/// -/// Reads meter login password from configured GCI data storage. -/// -public class MeterLoginPasswordReader : IMeterLoginPasswordReader +namespace GenesisCordonelInterface.Core.DataStorage.Reading.Implementation.MeterLoginPasswords { /// - /// Universal data storage reader selected by configuration. - /// Can represent database, CSV, JSON or REST reader. + /// Reads meter login password from configured GCI data storage. /// - private readonly IDataStorageReader reader; - - /// - /// Ensures that only one password lookup is executed at a time. - /// - private readonly SemaphoreSlim readLock = new SemaphoreSlim(1, 1); - - /// - /// Creates password reader using provided data storage configuration. - /// - /// Data storage configuration loaded from gci_config.json. - public MeterLoginPasswordReader(DataStorageConfig config) + public class MeterLoginPasswordReader : IMeterLoginPasswordReader { - reader = DataStorageReaderFactory.Create(config); - } + /// + /// Universal data storage reader selected by configuration. + /// Can represent database, CSV, JSON or REST reader. + /// + private readonly IDataStorageReader reader; - /// - /// Asynchronously reads meter login password by query parameter. - /// - /// PCB ID or another configured lookup value. - /// Cancellation token. - /// Password if found; otherwise null. - public async Task GetPasswordAsync( - string queryParam, - CancellationToken token = default) - { - if (string.IsNullOrWhiteSpace(queryParam)) - throw new ArgumentException("Query parameter must not be empty.", nameof(queryParam)); + /// + /// Ensures that only one password lookup is executed at a time. + /// + private readonly SemaphoreSlim readLock = new SemaphoreSlim(1, 1); - await readLock.WaitAsync(token); - - try + /// + /// Creates password reader using provided data storage configuration. + /// + /// Data storage configuration loaded from gci_config.json. + public MeterLoginPasswordReader(DataStorageConfig config) { - return await Task.Run( - () => GetPassword(queryParam), - token); - } - finally - { - readLock.Release(); - } - } - - /// - /// Reads meter login password by query parameter. - /// - /// PCB ID or another configured lookup value. - /// Password if found; otherwise null. - public string GetPassword(string queryParam) - { - if (string.IsNullOrWhiteSpace(queryParam)) - throw new ArgumentException("Query parameter must not be empty.", nameof(queryParam)); - - DataQuery query = new DataQuery(); - query.QueryParams.Add(queryParam); - - object result = reader.GetData(query); - - if (result is ReaderDiagnosticResult csvResult) - return csvResult.Data?.ToString(); - - if (result is DatabaseSearchResult dbResult) - { - if (!dbResult.Found || dbResult.Values == null || dbResult.Values.Count == 0) - return null; - - foreach (object value in dbResult.Values.Values) - return value?.ToString(); + reader = DataStorageReaderFactory.Create(config); } - return result?.ToString(); + /// + /// Asynchronously reads meter login password using + /// the provided data query. + /// + /// Thread-safe implementation may serialize + /// access to the underlying storage. + /// + /// + /// Data query containing lookup parameter values. + /// + /// + /// Cancellation token. + /// + /// + /// Password if found; otherwise null. + /// + public async Task ReadMeterLoginPasswordAsync( + DataQuery query, + CancellationToken token = default) + { + if (query == null) + throw new ArgumentNullException(nameof(query)); + + if (query.QueryParams.Count == 0) + throw new ArgumentException( + "Query does not contain any parameter.", + nameof(query)); + + await readLock.WaitAsync(token); + + try + { + return await Task.Run( + () => GetPassword(query), + token); + } + finally + { + readLock.Release(); + } + } + + /// + /// Reads meter login password using + /// the provided data query. + /// + /// + /// Data query containing lookup parameter values. + /// + /// + /// Password if found; otherwise null. + /// + public string GetPassword( + DataQuery query) + { + if (query == null) + throw new ArgumentNullException(nameof(query)); + + if (query.QueryParams.Count == 0) + throw new ArgumentException( + "Query does not contain any parameter.", + nameof(query)); + + object result = + reader.GetData(query); + + if (result is ReaderDiagnosticResult diagnosticResult) + { + return diagnosticResult.Data?.ToString(); + } + + if (result is DatabaseSearchResult dbResult) + { + if (!dbResult.Found || + dbResult.Values == null || + dbResult.Values.Count == 0) + { + return null; + } + + foreach (object value in dbResult.Values.Values) + { + return value?.ToString(); + } + } + + return result?.ToString(); + } } } \ No newline at end of file diff --git a/GenesisCordonelInterface/Core/DataStorage/Reading/Implementation/PreAdjustmentCalibrationParams/IPreAdjustmentCalibrationParamsReader.cs b/GenesisCordonelInterface/Core/DataStorage/Reading/Implementation/PreAdjustmentCalibrationParams/IPreAdjustmentCalibrationParamsReader.cs index 4063f4d4e..239d51d82 100644 --- a/GenesisCordonelInterface/Core/DataStorage/Reading/Implementation/PreAdjustmentCalibrationParams/IPreAdjustmentCalibrationParamsReader.cs +++ b/GenesisCordonelInterface/Core/DataStorage/Reading/Implementation/PreAdjustmentCalibrationParams/IPreAdjustmentCalibrationParamsReader.cs @@ -1,43 +1,62 @@ -using System.Collections.Generic; +using GenesisCordonelInterface.Core.DataStorage.Reading.Common.Models; +using System; +using System.Collections.Generic; +using System.Threading; using System.Threading.Tasks; namespace GenesisCordonelInterface.Core.DataStorage.Reading.Implementation.PreAdjustmentCalibrationParams { /// /// Provides access to pre-adjustment calibration parameters - /// stored in the configured data source. + /// stored in the configured GCI data source. /// /// Expected structure: - /// Dn_InternalId | ParameterName | ParameterValue + /// + /// MeterSize | ParameterName | ParameterValue /// /// Example: - /// 3 | GENESISFLOW_MinValidToF | 21990232 - /// 3 | GENESISFLOW_Timeout | 1 /// - /// Parameters are grouped by Dn_InternalId and returned + /// 2 | GENESISFLOW_MinValidToF | 21990232 + /// 2 | GENESISFLOW_Timeout | 1 + /// + /// Parameters are grouped by MeterSize and returned /// as key/value pairs where: /// /// Key = ParameterName /// Value = ParameterValue /// - internal interface IPreAdjustmentCalibrationParamsReader + public interface IPreAdjustmentCalibrationParamsReader { /// - /// Reads all calibration parameters assigned - /// to a specific DN identifier. + /// Reads all pre-adjustment calibration parameters + /// using the provided data query synchronously. /// - /// - /// Internal DN identifier (meter size). + /// + /// Data query containing meter size as lookup parameter. /// /// - /// Dictionary: - /// - /// Key: - /// GENESISFLOW parameter name - /// - /// Value: - /// Stored parameter value + /// Dictionary where key is GENESISFLOW parameter name + /// and value is stored parameter value. /// - Task> ReadParamsAsync(int dnInternalId); + Dictionary GetCalibrationParams( + DataQuery query); + + /// + /// Reads all pre-adjustment calibration parameters + /// using the provided data query asynchronously. + /// + /// + /// Data query containing meter size as lookup parameter. + /// + /// + /// Cancellation token. + /// + /// + /// Dictionary where key is GENESISFLOW parameter name + /// and value is stored parameter value. + /// + Task> ReadCalibrationParamsAsync( + DataQuery query, + CancellationToken token = default); } } \ No newline at end of file diff --git a/GenesisCordonelInterface/Core/DataStorage/Reading/Implementation/PreAdjustmentCalibrationParams/PreAdjustmentCalibrationParamsReader.cs b/GenesisCordonelInterface/Core/DataStorage/Reading/Implementation/PreAdjustmentCalibrationParams/PreAdjustmentCalibrationParamsReader.cs index 5e9ff3b7d..ad79e7490 100644 --- a/GenesisCordonelInterface/Core/DataStorage/Reading/Implementation/PreAdjustmentCalibrationParams/PreAdjustmentCalibrationParamsReader.cs +++ b/GenesisCordonelInterface/Core/DataStorage/Reading/Implementation/PreAdjustmentCalibrationParams/PreAdjustmentCalibrationParamsReader.cs @@ -1,87 +1,305 @@ -using System; +using GenesisCordonelInterface.Core.DataStorage.Reading.Common; +using GenesisCordonelInterface.Core.DataStorage.Reading.Common.Contracts; +using GenesisCordonelInterface.Core.DataStorage.Reading.Common.Models; +using System; using System.Collections.Generic; -using System.Data.SqlClient; +using System.Threading; using System.Threading.Tasks; namespace GenesisCordonelInterface.Core.DataStorage.Reading.Implementation.PreAdjustmentCalibrationParams { /// /// Reads pre-adjustment calibration parameters - /// from SQL database storage. + /// from configured GCI data storage. /// - /// Expected table: + /// The underlying storage type is selected + /// through IDataStorageReader and may represent: /// - /// dbo.PreAdjustmentCalibrationParams + /// - SQL database + /// - CSV + /// - JSON + /// - REST API /// - /// Columns: - /// Dn_InternalId - /// ParameterName - /// ParameterValue + /// Expected storage structure: + /// + /// MeterSize | ParameterName | ParameterValue /// /// Example: /// - /// 3 | GENESISFLOW_MinValidToF | 21990232 - /// 3 | GENESISFLOW_Timeout | 1 + /// 2 | GENESISFLOW_MinValidToF | 21990232 + /// 2 | GENESISFLOW_Timeout | 1 /// - /// Returns values as dictionary: + /// Returned data are represented as: /// - /// GENESISFLOW_MinValidToF -> 21990232 - /// GENESISFLOW_Timeout -> 1 + /// Key = ParameterName + /// Value = ParameterValue /// - internal class PreAdjustmentCalibrationParamsReader: IPreAdjustmentCalibrationParamsReader + public class PreAdjustmentCalibrationParamsReader + : IPreAdjustmentCalibrationParamsReader { - private readonly string _connectionString; + /// + /// Universal data storage reader selected by configuration. + /// Can represent database, CSV, JSON or REST reader. + /// + private readonly IDataStorageReader reader; /// - /// Initializes calibration parameter reader. + /// Ensures that only one calibration parameter lookup + /// is executed at a time. /// - /// - /// SQL database connection string. + private readonly SemaphoreSlim readLock = + new SemaphoreSlim(1, 1); + + /// + /// Creates calibration parameter reader using + /// provided data storage configuration. + /// + /// + /// Data storage configuration loaded from gci_config.json. /// public PreAdjustmentCalibrationParamsReader( - string connectionString) + DataStorageConfig config) { - _connectionString = connectionString?? throw new ArgumentNullException(nameof(connectionString)); + if (config == null) + throw new ArgumentNullException(nameof(config)); + + reader = DataStorageReaderFactory.Create(config); } - /// - public async Task> ReadParamsAsync(int dnInternalId) + /// + /// Reads all pre-adjustment calibration parameters + /// using the provided data query asynchronously. + /// + /// The query is expected to contain meter size + /// as the first lookup parameter. + /// + /// + /// Data query containing lookup parameter values. + /// + /// + /// Cancellation token. + /// + /// + /// Dictionary: + /// + /// Key: + /// GENESISFLOW parameter name + /// + /// Value: + /// Stored parameter value + /// + public async Task> ReadCalibrationParamsAsync( + DataQuery query, + CancellationToken token = default) { - var result = new Dictionary(); + ValidateQuery(query); - const string query = @" - SELECT ParameterName, ParameterValue - FROM dbo.PreAdjustmentCalibrationParams - WHERE Dn_InternalId=@Dn_InternalId"; + return await Task.Run( + () => GetCalibrationParams(query), + token).ConfigureAwait(false); ; - using (var connection = new SqlConnection(_connectionString)) + /*await readLock.WaitAsync(token); - using (var command = new SqlCommand(query, connection)) + try { - command.Parameters.AddWithValue( - "@Dn_InternalId", - dnInternalId); + return await Task.Run( + () => GetCalibrationParams(query), + token); + } + finally + { + readLock.Release(); + }*/ + } - await connection.OpenAsync(); + /// + /// Reads all pre-adjustment calibration parameters + /// using the provided data query. + /// + /// The query is expected to contain meter size + /// as the first lookup parameter. + /// + /// + /// Data query containing lookup parameter values. + /// + /// + /// Dictionary: + /// + /// Key: + /// GENESISFLOW parameter name + /// + /// Value: + /// Stored parameter value + /// + public Dictionary GetCalibrationParams( + DataQuery query) + { + ValidateQuery(query); - using (var reader = - await command.ExecuteReaderAsync()) + object result = + reader.GetData(query); + + return ConvertResultToDictionary(result); + } + + /// + /// Validates that data query exists + /// and contains at least one lookup parameter. + /// + /// + /// Data query to validate. + /// + private static void ValidateQuery( + DataQuery query) + { + if (query == null) + throw new ArgumentNullException(nameof(query)); + + if (query.QueryParams == null || + query.QueryParams.Count == 0) + { + throw new ArgumentException( + "Query does not contain any parameter.", + nameof(query)); + } + } + + /// + /// Converts provider-specific result objects + /// returned by IDataStorageReader into a unified + /// dictionary representation. + /// + /// + /// Raw result returned by the configured storage reader. + /// + /// + /// Dictionary containing calibration parameter + /// name/value pairs. + /// + private Dictionary ConvertResultToDictionary( + object result) + { + Dictionary values = + new Dictionary(); + + if (result == null) + return values; + + if (result is DatabaseSearchResult dbResult) + { + if (!dbResult.Found) + return values; + + foreach (Dictionary row in dbResult.Rows) { - while (await reader.ReadAsync()) + if (!row.TryGetValue("ParameterName", out object parameterNameObject)) + continue; + + if (!row.TryGetValue("ParameterValue", out object parameterValueObject)) + continue; + + string parameterName = + parameterNameObject?.ToString(); + + if (string.IsNullOrWhiteSpace(parameterName)) + continue; + + if (TryConvertToUInt32(parameterValueObject, out UInt32 parameterValue)) { - var parameterName = reader["ParameterName"].ToString(); - - var parameterValue = reader["ParameterValue"].ToString(); - - if (!string.IsNullOrWhiteSpace(parameterName)) - { - result[parameterName] = parameterValue; - } + values[parameterName] = + parameterValue; } } + + return values; + } + + if (result is ReaderDiagnosticResult diagnosticResult) + { + if (diagnosticResult.Data is Dictionary uintDictionary) + return uintDictionary; + + if (diagnosticResult.Data is Dictionary stringDictionary) + { + foreach (var item in stringDictionary) + { + if (TryConvertToUInt32(item.Value, out UInt32 value)) + values[item.Key] = value; + } + + return values; + } + + if (diagnosticResult.Data is Dictionary objectDictionary) + { + foreach (var item in objectDictionary) + { + if (TryConvertToUInt32(item.Value, out UInt32 value)) + values[item.Key] = value; + } + + return values; + } } - return result; + if (result is Dictionary directUIntDictionary) + return directUIntDictionary; + + if (result is Dictionary directStringDictionary) + { + foreach (var item in directStringDictionary) + { + if (TryConvertToUInt32(item.Value, out UInt32 value)) + values[item.Key] = value; + } + + return values; + } + + if (result is Dictionary directObjectDictionary) + { + foreach (var item in directObjectDictionary) + { + if (TryConvertToUInt32(item.Value, out UInt32 value)) + values[item.Key] = value; + } + } + + return values; + } + + private static bool TryConvertToUInt32( + object value, + out UInt32 result) + { + result = 0; + + if (value == null) + return false; + + if (value is UInt32 uintValue) + { + result = uintValue; + return true; + } + + if (value is int intValue && intValue >= 0) + { + result = Convert.ToUInt32(intValue); + return true; + } + + if (value is long longValue && + longValue >= 0 && + longValue <= UInt32.MaxValue) + { + result = Convert.ToUInt32(longValue); + return true; + } + + return UInt32.TryParse( + value.ToString(), + out result); } } } \ No newline at end of file diff --git a/GenesisCordonelInterface/Core/Engine/Engine.cs b/GenesisCordonelInterface/Core/Engine/Engine.cs new file mode 100644 index 000000000..0e2bae171 --- /dev/null +++ b/GenesisCordonelInterface/Core/Engine/Engine.cs @@ -0,0 +1,73 @@ +using GenesisCordonelInterface.API; +using GenesisCordonelInterface.Core.Config; +using GenesisCordonelInterface.Core.DataStorage.Reading.Common.Models; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Security.AccessControl; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; +using UdsReaderType_CalibrationParams = GenesisCordonelInterface.Core.DataStorage.Reading.Implementation.PreAdjustmentCalibrationParams.PreAdjustmentCalibrationParamsReader; +using UdsReaderType_LoginPasswords = GenesisCordonelInterface.Core.DataStorage.Reading.Implementation.MeterLoginPasswords.MeterLoginPasswordReader; +using GciPublicModels = GenesisCordonelInterface.API.PublicModels; +using GciEnums = GenesisCordonelInterface.API.Enums; +using GciType = GenesisCordonelInterface.API.InterfaceOutsideToGCI; +using GciDataStorageReadingModels = GenesisCordonelInterface.Core.DataStorage.Reading.Common.Models; +using GciGUIType = GenesisCordonelInterface.UI.MainView; + +namespace GenesisCordonelInterface.Core +{ + public class Engine + { + GciConfig gciConfig; + + public UdsReaderType_LoginPasswords loginPasswordsDataStorageReader; + public UdsReaderType_CalibrationParams calibrationParamsStorageReader; + //readonly UdsWriterType writer; + + //diag GUI for GCI + GciGUIType gciGUI; + Form gciGuiHostForm; + + //diag GUI for GciBridge + public UserControl gciBridgeGUIUserControl; + public UI.MainForm gciBridgeGuiForm; + + public InterfaceOutsideToGCI gciExternalInterface; + + /// + /// Initializes a new instance of the public GCI facade. + /// + public Engine() + { + gciConfig = GciConfigLoader.LoadDefault(); + + loginPasswordsDataStorageReader = new UdsReaderType_LoginPasswords + ( + new GciDataStorageReadingModels.DataStorageConfig + ( + nameof(GciEnums.DataStorageReaderTypes.LoginPasswordsReader), + GciDataStorageReadingModels.DataStorageType.LocalDatabase, + gciConfig.DataStorageSection.MeterLoginPasswords.DataSource, + gciConfig.DataStorageSection.MeterLoginPasswords.QueryTemplate + ) + ); + calibrationParamsStorageReader = new UdsReaderType_CalibrationParams + ( + new GciDataStorageReadingModels.DataStorageConfig + ( + nameof(GciEnums.DataStorageReaderTypes.CalibrationParamsReader), + GciDataStorageReadingModels.DataStorageType.LocalDatabase, + gciConfig.DataStorageSection.PreAdjustmentCalibrationParams.DataSource, + gciConfig.DataStorageSection.PreAdjustmentCalibrationParams.QueryTemplate + ) + ); + + gciExternalInterface = new InterfaceOutsideToGCI( + new InterfaceGCIToLaatzen(), + loginPasswordsDataStorageReader, + calibrationParamsStorageReader); + } + } +} diff --git a/GenesisCordonelInterface/GenesisCordonelInterface.csproj b/GenesisCordonelInterface/GenesisCordonelInterface.csproj index 4b9fefd99..d047f896b 100644 --- a/GenesisCordonelInterface/GenesisCordonelInterface.csproj +++ b/GenesisCordonelInterface/GenesisCordonelInterface.csproj @@ -60,9 +60,10 @@ - - + + + @@ -80,6 +81,7 @@ + @@ -200,9 +202,11 @@ FrmGCIAPI.cs - + + Config\gci_config.json PreserveNewest + @@ -245,6 +249,7 @@ + diff --git a/GenesisCordonelInterface/UI/Debug/MeterBatchConfigPanel.cs b/GenesisCordonelInterface/UI/Debug/MeterBatchConfigPanel.cs index a2b52d06e..b647bc9b6 100644 --- a/GenesisCordonelInterface/UI/Debug/MeterBatchConfigPanel.cs +++ b/GenesisCordonelInterface/UI/Debug/MeterBatchConfigPanel.cs @@ -122,22 +122,23 @@ namespace GenesisCordonelInterface.UI.Debug { isRefreshing = true; - foreach (var meter in data) - { - EnsurePortValueExists(meter.RequestPort); - EnsurePortValueExists(meter.StreamingPort); + if(data != null) + foreach (var meter in data) + { + EnsurePortValueExists(meter.RequestPort); + EnsurePortValueExists(meter.StreamingPort); - var row = FindOrCreateRow(meter.Slot); + var row = FindOrCreateRow(meter.Slot); - Set(row, "Slot", meter.Slot); - Set(row, "Selected", meter.Selected); - Set(row, "PcbId", meter.PcbId); - Set(row, "IsLoggedOn", meter.IsLoggedOn); - Set(row, "RequestPort", meter.RequestPort); - Set(row, "StreamingPort", meter.StreamingPort); - Set(row, "FwVersion", meter.FwVersion); - Set(row, "InterfaceVersion", meter.InterfaceVersion); - } + Set(row, "Slot", meter.Slot); + Set(row, "Selected", meter.Selected); + Set(row, "PcbId", meter.PcbId); + Set(row, "IsLoggedOn", meter.IsLoggedOn); + Set(row, "RequestPort", meter.RequestPort); + Set(row, "StreamingPort", meter.StreamingPort); + Set(row, "FwVersion", meter.FwVersion); + Set(row, "InterfaceVersion", meter.InterfaceVersion); + } isRefreshing = false; } diff --git a/GenesisCordonelInterface/bin/Debug/Config/gci_config.json b/GenesisCordonelInterface/bin/Debug/Config/gci_config.json new file mode 100644 index 000000000..0a25a6d34 --- /dev/null +++ b/GenesisCordonelInterface/bin/Debug/Config/gci_config.json @@ -0,0 +1,36 @@ +{ + "_Comment": "GCI DataStorage configuration", + + "DataStorageSection": { + + "MeterLoginPasswords": { + + "___Documentation___": { + "Description": "Reads login passwords for meters by PCB ID", + "Type": "Supported: LocalDatabase, RemoteDatabase, LocalCsv, LocalJson, RestApi", + "DataSource": "Database connection string", + "QueryTemplate": "QUERYPARAM is placeholder for runtime value. Example: WHERE [PcbId]=QUERYPARAM -> PCB ID provided during GetPasswordAsync()." + }, + + "Name": "MeterLoginPasswords", + "Type": "LocalDatabase", + "DataSource": "Server=(localdb)\\SensusLocalDB;Database=UnionTownCalibAndSkeleton;Integrated Security=True;", + "QueryTemplate": "SELECT [Password] FROM [dbo].[SkeletonKeys] WHERE [PcbId] = QUERYPARAM" + }, + + "PreAdjustmentCalibrationParams": { + + "___Documentation___": { + "Description": "Reads pre-adjustment calibration parameters by meter size", + "Type": "Supported: LocalDatabase, RemoteDatabase, LocalCsv, LocalJson, RestApi", + "DataSource": "Database connection string", + "QueryTemplate": "QUERYPARAM is placeholder for runtime value. Example: WHERE [MeterSize]=QUERYPARAM -> meter size provided during ReadCalibrationParamsAsync()." + }, + + "Name": "PreAdjustmentCalibrationParams", + "Type": "LocalDatabase", + "DataSource": "Server=(localdb)\\SensusLocalDB;Database=UnionTownCalibAndSkeleton;Integrated Security=True;", + "QueryTemplate": "SELECT [ParameterName], [ParameterValue] FROM [dbo].[PreAdjustmentCalibrationParams] WHERE [MeterSize] = QUERYPARAM" + } + } +} diff --git a/TBF/Rig/BridgeComponents/GciBridge/GciBridge.cs b/TBF/Rig/BridgeComponents/GciBridge/GciBridge.cs index 79473de67..2dbbeb851 100644 --- a/TBF/Rig/BridgeComponents/GciBridge/GciBridge.cs +++ b/TBF/Rig/BridgeComponents/GciBridge/GciBridge.cs @@ -1,8 +1,12 @@ using CordonelPreadjustmentUi; using CordonelPreadjustmentUi.Processes.Itinerary; using GenesisCordonelInterface.API; +using GenesisCordonelInterface.Core; +using GenesisCordonelInterface.Core.DataStorage.Reading.Common.Models; using GenesisCordonelInterface.Core.Threading; +using GraphLib; using log4net; +using NHibernate.Mapping; /// /// Copyright (c) 2015-2021 Sensus Slovensko a.s. /// @@ -20,10 +24,14 @@ 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 GciEngine = GenesisCordonelInterface.Core.Engine; +using GciEnums = GenesisCordonelInterface.API.Enums; using GciGUIType = GenesisCordonelInterface.UI.MainView; using GciPublicModels = GenesisCordonelInterface.API.PublicModels; using GciType = GenesisCordonelInterface.API.InterfaceOutsideToGCI; -using UdsReaderType = TBF.Rig.Input.DataStorage.UniDataStorageReader.Reader; +using GciUDSRPublicModels = GenesisCordonelInterface.Core.DataStorage.Reading.Common.Models; +using UdsReaderType_CalibrationParams = GenesisCordonelInterface.Core.DataStorage.Reading.Implementation.PreAdjustmentCalibrationParams.PreAdjustmentCalibrationParamsReader; +using UdsReaderType_LoginPasswords = GenesisCordonelInterface.Core.DataStorage.Reading.Implementation.MeterLoginPasswords.MeterLoginPasswordReader;//TBF.Rig.Input.DataStorageSection.UniDataStorageReader.Reader; using UDSRPublicModels = TBF.Rig.Input.DataStorage.UniDataStorageReader.Interfaces.PublicModels; using UdsWriterType = TBF.Rig.Output.DataStorage.UniDataStorageWriter.Writer; @@ -44,9 +52,12 @@ namespace TBF.Rig.BridgeComponents.GciBridge readonly GciBridgeCfg gciBridgeCfg; - readonly UdsReaderType reader; + readonly Reader reader; readonly UdsWriterType writer; + //GCI main init + public GciEngine _gciEngine; + //diag GUI for GCI GciGUIType gciGUI; Form gciGuiHostForm; @@ -55,18 +66,18 @@ namespace TBF.Rig.BridgeComponents.GciBridge public UserControl gciBridgeGUIUserControl; public UI.MainForm gciBridgeGuiForm; - public GciType gciExternalInterface; - - public bool HasReader { get { return reader != null; } } - public bool HasWriter { get { return writer != null; } } public bool IsGuiInitialized { get { return gciGUI != null; } } - public bool IsExternalInitialized { get { return gciExternalInterface != null; } } - public GciType GciExternalInterface { get { return gciExternalInterface; } } + public bool IsExternalInitialized { get { return _gciEngine.gciExternalInterface != null; } } + public GciType gciExternalInterface { get { return _gciEngine.gciExternalInterface; } } public GciBridgeCfg GciBridgeCfg { get { return gciBridgeCfg; } } - public UdsReaderType GetReader() + public UdsReaderType_LoginPasswords GetLoginPasswordsDataStorageReader() { - return reader; + return _gciEngine.loginPasswordsDataStorageReader; + } + public UdsReaderType_CalibrationParams GetCalibrationParamsStorageReader() + { + return _gciEngine.calibrationParamsStorageReader; } public UdsWriterType GetWriter() @@ -84,7 +95,7 @@ namespace TBF.Rig.BridgeComponents.GciBridge if (!string.IsNullOrEmpty(gciBridgeCfg.ReaderName)) { - reader = TbfComponents.FindComponent(gciBridgeCfg.ReaderName, components) as UdsReaderType; + reader = TbfComponents.FindComponent(gciBridgeCfg.ReaderName, components) as Reader; if (reader == null) throw new Exception("Cannot find reader component '" + gciBridgeCfg.ReaderName + "'"); } @@ -94,6 +105,8 @@ namespace TBF.Rig.BridgeComponents.GciBridge if (writer == null) throw new Exception("Cannot find writer component '" + gciBridgeCfg.WriterName + "'"); } + _gciEngine = new GciEngine(); + Initialize(); } @@ -130,17 +143,6 @@ namespace TBF.Rig.BridgeComponents.GciBridge gciBridgeGuiForm.Height = 600; gciBridgeGuiForm.StartPosition = FormStartPosition.CenterScreen; - /*gciBridgeGUI = new MainView(this, gciBridgeGuiForm); - gciBridgeGUI.Dock = DockStyle.Fill; - - gciBridgeGuiForm.Controls.Add(gciBridgeGUI); - - gciBridgeGuiForm.FormClosed += (s, e) => - { - gciBridgeGUI = null; - gciBridgeGuiForm = null; - };*/ - log.InfoFormat("{0}: GciBridge GUI view initialized.", Name); } catch (Exception ex) @@ -179,10 +181,10 @@ namespace TBF.Rig.BridgeComponents.GciBridge { try { - if (gciExternalInterface != null) + if (_gciEngine.gciExternalInterface != null) return; - gciExternalInterface = new GciType(); + _gciEngine.gciExternalInterface = new GciType(); log.InfoFormat("{0}: GCI external interface initialized.", Name); } @@ -255,14 +257,15 @@ namespace TBF.Rig.BridgeComponents.GciBridge if (!IsExternalInitialized) TryInitializeExternalInterface(); - if (gciExternalInterface == null) + if (_gciEngine.gciExternalInterface == null) throw new Exception("GCI external interface is not initialized."); } void EnsureReader() { - if (reader == null) - throw new Exception("UniDataStorageReader is not linked to GciBridge."); + /*if (reader == null) + throw new Exception("UniDataStorageReader is not linked to GciBridge.");*/ + } // API: @@ -293,7 +296,7 @@ namespace TBF.Rig.BridgeComponents.GciBridge if (request.SlotId <= 0) throw new ArgumentException("Invalid slot id.", nameof(request)); - var result = await gciExternalInterface + var result = await _gciEngine.gciExternalInterface .InitSlotAsync(request, token) .ConfigureAwait(false); @@ -374,7 +377,7 @@ namespace TBF.Rig.BridgeComponents.GciBridge if (request.SlotId <= 0) throw new ArgumentException("Invalid slot id.", nameof(request)); - var result = await gciExternalInterface + var result = await _gciEngine.gciExternalInterface .UpdateSlotAsync(request, token) .ConfigureAwait(false); @@ -450,7 +453,7 @@ namespace TBF.Rig.BridgeComponents.GciBridge throw new ArgumentException("Invalid slot id."); GciPublicModels.GciSlotInfo result = - await gciExternalInterface.GetSlotAsync(slotId, token); + await _gciEngine.gciExternalInterface.GetSlotAsync(slotId, token); log.InfoFormat("{0}: GetSlotAsync({1}) invoked. Result={2}", Name, slotId, result); @@ -526,7 +529,7 @@ namespace TBF.Rig.BridgeComponents.GciBridge throw new ArgumentException("Invalid slot id.", nameof(slot)); GciPublicModels.GciCleanSlotResult result = - await gciExternalInterface.CleanSlotAsync(slot, token); + await _gciEngine.gciExternalInterface.CleanSlotAsync(slot, token); log.InfoFormat("{0}: CleanSlotAsync invoked. Slot={1}, Result={2}", Name, slot, result); @@ -599,7 +602,7 @@ namespace TBF.Rig.BridgeComponents.GciBridge EnsureExternalInterface(); GciPublicModels.GciCleanAllSlotsResult result = - await gciExternalInterface.CleanAllSlotsAsync(token); + await _gciEngine.gciExternalInterface.CleanAllSlotsAsync(token); log.InfoFormat("{0}: CleanAllSlotsAsync invoked.", Name); @@ -673,7 +676,7 @@ namespace TBF.Rig.BridgeComponents.GciBridge if (slotId <= 0) throw new ArgumentException("Invalid slot id.", nameof(slotId)); - var result = await gciExternalInterface + var result = await _gciEngine.gciExternalInterface .GetPcbIdAsync(slotId, token) .ConfigureAwait(false); @@ -790,7 +793,7 @@ namespace TBF.Rig.BridgeComponents.GciBridge if (slot <= 0) throw new ArgumentException("Invalid slot id.", nameof(slot)); - var result = await gciExternalInterface + var result = await _gciEngine.gciExternalInterface .ConnectOneSlotAsync(slot, token) .ConfigureAwait(false); @@ -822,7 +825,7 @@ namespace TBF.Rig.BridgeComponents.GciBridge if (slotId <= 0) throw new ArgumentException("Invalid slot id."); - var result = await gciExternalInterface.LoginOneSlotAsync(slotId, token); + var result = await _gciEngine.gciExternalInterface.LoginOneSlotAsync(slotId, token); log.InfoFormat("{0}: LoginAsync({1}) invoked. Result={2}", Name, slotId, result); @@ -893,7 +896,7 @@ namespace TBF.Rig.BridgeComponents.GciBridge if (slotId <= 0) throw new ArgumentException("Invalid slot id."); - var result = await gciExternalInterface.DisconnectAsync(slotId, token); + var result = await _gciEngine.gciExternalInterface.DisconnectAsync(slotId, token); log.InfoFormat("{0}: DisconnectAsync({1}) invoked. Result={2}", Name, slotId, result); @@ -976,7 +979,7 @@ namespace TBF.Rig.BridgeComponents.GciBridge throw new ArgumentException("Password is empty."); GciPublicModels.GciSetPasswordResult result = - await gciExternalInterface.SetPasswordAsync(slotId, password, token); + await _gciEngine.gciExternalInterface.SetPasswordAsync(slotId, password, token); log.InfoFormat("{0}: SetPasswordAsync({1}) invoked. Result={2}", Name, slotId, result); @@ -1051,7 +1054,7 @@ namespace TBF.Rig.BridgeComponents.GciBridge if (string.IsNullOrWhiteSpace(registerName)) throw new ArgumentException("Register name is empty."); - var result = await gciExternalInterface.ReadRegisterAsync(slotId, registerName, token); + var result = await _gciEngine.gciExternalInterface.ReadRegisterAsync(slotId, registerName, token); log.InfoFormat("{0}: ReadRegisterAsync({1}, {2}) invoked. Result={3}", Name, slotId, registerName, result); @@ -1141,7 +1144,7 @@ namespace TBF.Rig.BridgeComponents.GciBridge if (string.IsNullOrWhiteSpace(registerName)) throw new ArgumentException("Register name is empty."); - var result = await gciExternalInterface.WriteRegisterAsync( + var result = await _gciEngine.gciExternalInterface.WriteRegisterAsync( slotId, registerName, value, @@ -1222,7 +1225,7 @@ namespace TBF.Rig.BridgeComponents.GciBridge /// Reads password data from UniDataStorageReader by PCB ID. /// /// Trace: - /// GciBridge.GetPasswordAsync() + /// GciBridge.ReadMeterLoginPasswordAsync() /// -> UniDataStorageReader.Reader.GetDataFromStorageByParameterAsync() /// -> Reader queue/lock /// -> Reader.GetDataFromStorageByParameter() @@ -1239,13 +1242,13 @@ namespace TBF.Rig.BridgeComponents.GciBridge EnsureReader(); if (string.IsNullOrWhiteSpace(pcbId)) - throw new ArgumentException("PCB ID is empty.", nameof(pcbId)); + throw new ArgumentException("PCB ID is empty.", nameof(pcbId)); try { - UDSRPublicModels.DataQuery query = CreatePasswordQuery(pcbId); + GciUDSRPublicModels.DataQuery query = CreatePasswordQuery(pcbId); - object data = await reader.GetDataFromStorageByParameterAsync(query, token); + object data = await _gciEngine.gciExternalInterface.ReadMeterLoginPasswordAsync(query, token); string password = ExtractPassword(data); @@ -1261,7 +1264,7 @@ namespace TBF.Rig.BridgeComponents.GciBridge } catch (Exception ex) { - log.Error("GetPasswordAsync failed.", ex); + log.Error("ReadMeterLoginPasswordAsync failed.", ex); return new UdsPasswordResult { @@ -1273,7 +1276,132 @@ namespace TBF.Rig.BridgeComponents.GciBridge } } + /// + /// Reads pre-adjustment calibration parameters + /// from UniDataStorageReader by meter size. + /// + /// Trace: + /// GciBridge.GetPreAdjustmentCalibrationParamsAsync() + /// -> UniDataStorageReader.Reader.GetDataFromStorageByParameterAsync() + /// -> Reader queue/lock + /// -> Reader.GetDataFromStorageByParameter() + /// -> selected storage reader by configuration + /// -> DatabaseReader.GetData() + /// -> RestApiReader.GetData() + /// -> JsonReader.GetData() + /// -> CsvReader.GetData() + /// + /// Expected result: + /// + /// Key: + /// Calibration parameter name + /// + /// Value: + /// Calibration parameter value + /// + /// Example: + /// + /// GENESISFLOW_MinValidToF -> 13743895 + /// GENESISFLOW_Timeout -> 1 + /// + /// + /// Meter size used as query parameter. + /// + /// + /// Cancellation token. + /// + /// + /// Calibration parameter lookup result. + /// + public async Task GetPreAdjustmentCalibrationParamsAsync( + int meterSize, + CancellationToken token = default) + { + EnsureReader(); + if (meterSize < 0) + throw new ArgumentException( + "Meter size must not be negative.", + nameof(meterSize)); + + try + { + GciUDSRPublicModels.DataQuery query = CreatePreAdjustmentCalibrationParamsQuery(meterSize); + + object data = await _gciEngine.gciExternalInterface.ReadPreAdjustmentCalibrationParamsAsync(query, token); + + Dictionary calibrationParams = + ExtractPreAdjustmentCalibrationParams(data); + + return new UdsPreAdjustmentCalibrationParamsResult + { + Success = calibrationParams != null && + calibrationParams.Count > 0, + MeterSize = meterSize, + CalibrationParams = calibrationParams, + Message = calibrationParams != null && + calibrationParams.Count > 0 + ? "Pre-adjustment calibration parameters found." + : "Pre-adjustment calibration parameters were not found." + }; + } + catch (Exception ex) + { + log.Error( + "GetPreAdjustmentCalibrationParamsAsync failed.", + ex); + + return new UdsPreAdjustmentCalibrationParamsResult + { + Success = false, + MeterSize = meterSize, + CalibrationParams = null, + Message = ex.Message + }; + } + } + + private GciUDSRPublicModels.DataQuery CreatePreAdjustmentCalibrationParamsQuery( + int meterSize) + { + GciUDSRPublicModels.DataQuery query = + new GciUDSRPublicModels.DataQuery(); + + query.QueryParams.Add( + meterSize.ToString()); + + return query; + } + + private Dictionary ExtractPreAdjustmentCalibrationParams( + object data) + { + Dictionary result = + new Dictionary(); + + if (data == null) + return result; + + if (data is Dictionary directDictionary) + return directDictionary; + + if (data is Dictionary objectDictionary) + { + foreach (var item in objectDictionary) + { + if (UInt32.TryParse( + item.Value?.ToString(), + out UInt32 value)) + { + result[item.Key] = value; + } + } + + return result; + } + + return result; + } /// /// Reads password from UniDataStorageReader using PCB ID with retry support. @@ -1288,7 +1416,7 @@ namespace TBF.Rig.BridgeComponents.GciBridge /// /// GetPasswordWithRetryAsync() /// -> RetryWorker.RunWithRetryAsync() - /// -> GetPasswordAsync() + /// -> ReadMeterLoginPasswordAsync() /// -> UniDataStorageReader /// /// Returns: @@ -1310,7 +1438,7 @@ namespace TBF.Rig.BridgeComponents.GciBridge r => r.Success, msg => log.Info(msg), (msg, result) => log.InfoFormat("{0}: {1}", msg, result), - $"GetPasswordAsync pcb {pcbId}", + $"ReadMeterLoginPasswordAsync pcb {pcbId}", maxAttempts: 5, delayMs: 5, timeoutMs: 30000); @@ -1362,7 +1490,7 @@ namespace TBF.Rig.BridgeComponents.GciBridge /// -> RetryWorker.RunWithRetryAsync() /// -> ConnectAsync() /// -> GetPcbIdAsync() - /// -> GetPasswordAsync() + /// -> ReadMeterLoginPasswordAsync() /// -> SetPasswordAsync() /// -> LoginAsync() /// @@ -1393,7 +1521,7 @@ namespace TBF.Rig.BridgeComponents.GciBridge RetryWorker.EnsureSuccess(finalResult.PcbResult, $"GetPcbIdAsync slot {slotId}"); finalResult.PasswordResult = await GetPasswordWithRetryAsync(finalResult.PcbResult.Result.PcbId, token); - RetryWorker.EnsureSuccess(finalResult.PasswordResult, $"GetPasswordAsync slot {slotId}"); + RetryWorker.EnsureSuccess(finalResult.PasswordResult, $"ReadMeterLoginPasswordAsync slot {slotId}"); finalResult.SetPasswordResult = await SetPasswordWithRetryAsync(slotId, finalResult.PasswordResult.Result.Password, token); RetryWorker.EnsureSuccess(finalResult.SetPasswordResult, $"SetPasswordAsync slot {slotId}"); @@ -1442,7 +1570,7 @@ namespace TBF.Rig.BridgeComponents.GciBridge Name, operation); - PreAdjustmentInitializationResult result = gciExternalInterface.Preadjustment_Initialization(pp, mc); + PreAdjustmentInitializationResult result = _gciEngine.gciExternalInterface.Preadjustment_Initialization(pp, mc); log.InfoFormat( "{0}: {1} Finish. {2}", @@ -1486,7 +1614,7 @@ namespace TBF.Rig.BridgeComponents.GciBridge log.InfoFormat("{0}: {1} Start.", Name, operation); PreadjustmentDetectResult result = - await gciExternalInterface + await _gciEngine.gciExternalInterface .PreAdjustment_DetectAsync(selectedSlots, token) .ConfigureAwait(false); @@ -1512,6 +1640,36 @@ namespace TBF.Rig.BridgeComponents.GciBridge } } + public PreadjustmentDetectResult PreAdjustment_DetectDirect( + IEnumerable selectedSlots, + CancellationToken token = default) + { + const string operation = nameof(PreAdjustment_DetectDirect); + + try + { + EnsureExternalInterface(); + + log.InfoFormat("{0}: {1} Start.", Name, operation); + + PreadjustmentDetectResult result = _gciEngine.gciExternalInterface.PreAdjustment_DetectDirect(selectedSlots, token); + + log.InfoFormat("{0}: {1} Finish. {2}", Name, operation, result); + + return result; + } + catch (Exception ex) + { + log.Error($"{Name}: {operation} failed.", ex); + + return new PreadjustmentDetectResult + { + Success = false, + ErrorMessage = ex.Message + }; + } + } + #endregion #region ================================== PreAdjustment PREPARATION bridge ================================== @@ -1533,7 +1691,7 @@ namespace TBF.Rig.BridgeComponents.GciBridge slot); PreAdjustmentProcessResult result = - await gciExternalInterface + await _gciEngine.gciExternalInterface .PreAdjustment_PreparationAsync( slot, token) @@ -1563,6 +1721,35 @@ namespace TBF.Rig.BridgeComponents.GciBridge } } + public PreAdjustmentProcessResult PreAdjustment_PreparationDirect() + { + const string operation = nameof(PreAdjustment_PreparationDirect); + + try + { + EnsureExternalInterface(); + + log.InfoFormat("{0}: {1} Start.", Name, operation); + + PreAdjustmentProcessResult result = _gciEngine.gciExternalInterface.PreAdjustment_PreparationDirect(); + + log.InfoFormat("{0}: {1} Finish. {2}", Name, operation, result); + + return result; + } + catch (Exception ex) + { + log.Error($"{Name}: {operation} failed.", ex); + + return new PreAdjustmentProcessResult + { + Success = false, + ProcessName = "Preparation", + ErrorMessage = ex.Message + }; + } + } + #endregion #region ================================== PreAdjustment AMPLITUDE TEST bridge ================================== @@ -1584,7 +1771,7 @@ namespace TBF.Rig.BridgeComponents.GciBridge slot); PreAdjustmentProcessResult result = - await gciExternalInterface + await _gciEngine.gciExternalInterface .PreAdjustment_AmplitudeTestAsync( slot, token) @@ -1614,6 +1801,35 @@ namespace TBF.Rig.BridgeComponents.GciBridge } } + public PreAdjustmentProcessResult PreAdjustment_AmplitudeTestDirect() + { + const string operation = nameof(PreAdjustment_AmplitudeTestDirect); + + try + { + EnsureExternalInterface(); + + log.InfoFormat("{0}: {1} Start.", Name, operation); + + PreAdjustmentProcessResult result = _gciEngine.gciExternalInterface.PreAdjustment_AmplitudeTestDirect(); + + log.InfoFormat("{0}: {1} Finish. {2}", Name, operation, result); + + return result; + } + catch (Exception ex) + { + log.Error($"{Name}: {operation} failed.", ex); + + return new PreAdjustmentProcessResult + { + Success = false, + ProcessName = "AmplitudeTest", + ErrorMessage = ex.Message + }; + } + } + #endregion #region ================================== PreAdjustment TEMPERATURE CALIBRATION bridge ================================== @@ -1635,7 +1851,7 @@ namespace TBF.Rig.BridgeComponents.GciBridge slot); PreAdjustmentProcessResult result = - await gciExternalInterface + await _gciEngine.gciExternalInterface .PreAdjustment_TemperatureCalibrationAsync( slot, token) @@ -1665,6 +1881,62 @@ namespace TBF.Rig.BridgeComponents.GciBridge } } + public bool PreAdjustment_PushTemperature( + double temperature) + { + const string operation = nameof(PreAdjustment_PushTemperature); + + try + { + EnsureExternalInterface(); + + log.InfoFormat( + "{0}: {1}. Temperature={2}", + Name, + operation, + temperature); + + return _gciEngine.gciExternalInterface.PreAdjustment_PushTemperature(temperature); + } + catch (Exception ex) + { + log.Error( + string.Format("{0}: {1} failed.", Name, operation), + ex); + + return false; + } + } + + public PreAdjustmentProcessResult PreAdjustment_TemperatureCalibrationDirect() + { + const string operation = nameof(PreAdjustment_TemperatureCalibrationDirect); + + try + { + EnsureExternalInterface(); + + log.InfoFormat("{0}: {1} Start.", Name, operation); + + PreAdjustmentProcessResult result = _gciEngine.gciExternalInterface.PreAdjustment_TemperatureCalibrationDirect(); + + log.InfoFormat("{0}: {1} Finish. {2}", Name, operation, result); + + return result; + } + catch (Exception ex) + { + log.Error($"{Name}: {operation} failed.", ex); + + return new PreAdjustmentProcessResult + { + Success = false, + ProcessName = "TemperatureCalibration", + ErrorMessage = ex.Message + }; + } + } + #endregion #region ================================== PreAdjustment OFFSET TEST bridge ================================== @@ -1686,7 +1958,7 @@ namespace TBF.Rig.BridgeComponents.GciBridge slot); PreAdjustmentProcessResult result = - await gciExternalInterface + await _gciEngine.gciExternalInterface .PreAdjustment_OffsetTestAsync( slot, token) @@ -1716,6 +1988,35 @@ namespace TBF.Rig.BridgeComponents.GciBridge } } + public PreAdjustmentProcessResult PreAdjustment_OffsetTestDirect() + { + const string operation = nameof(PreAdjustment_OffsetTestDirect); + + try + { + EnsureExternalInterface(); + + log.InfoFormat("{0}: {1} Start.", Name, operation); + + PreAdjustmentProcessResult result = _gciEngine.gciExternalInterface.PreAdjustment_OffsetTestDirect(); + + log.InfoFormat("{0}: {1} Finish. {2}", Name, operation, result); + + return result; + } + catch (Exception ex) + { + log.Error($"{Name}: {operation} failed.", ex); + + return new PreAdjustmentProcessResult + { + Success = false, + ProcessName = "OffsetTest", + ErrorMessage = ex.Message + }; + } + } + #endregion #region ================================== PreAdjustment COMPLETION bridge ================================== @@ -1737,7 +2038,7 @@ namespace TBF.Rig.BridgeComponents.GciBridge slot); PreAdjustmentProcessResult result = - await gciExternalInterface + await _gciEngine.gciExternalInterface .PreAdjustment_CompletionAsync( slot, token) @@ -1767,12 +2068,41 @@ namespace TBF.Rig.BridgeComponents.GciBridge } } + public PreAdjustmentProcessResult PreAdjustment_CompletionDirect() + { + const string operation = nameof(PreAdjustment_CompletionDirect); + + try + { + EnsureExternalInterface(); + + log.InfoFormat("{0}: {1} Start.", Name, operation); + + PreAdjustmentProcessResult result = _gciEngine.gciExternalInterface.PreAdjustment_CompletionDirect(); + + log.InfoFormat("{0}: {1} Finish. {2}", Name, operation, result); + + return result; + } + catch (Exception ex) + { + log.Error($"{Name}: {operation} failed.", ex); + + return new PreAdjustmentProcessResult + { + Success = false, + ProcessName = "Completion", + ErrorMessage = ex.Message + }; + } + } + #endregion #region ======================================= Helpers ======================================= - private UDSRPublicModels.DataQuery CreatePasswordQuery(string pcbId) + private GciUDSRPublicModels.DataQuery CreatePasswordQuery(string pcbId) { - var query = new UDSRPublicModels.DataQuery(); + var query = new GciUDSRPublicModels.DataQuery(); query.QueryParams.Add(pcbId); return query; } @@ -1807,7 +2137,7 @@ namespace TBF.Rig.BridgeComponents.GciBridge public List GetAllRegisterNames() { EnsureExternalInterface(); - return gciExternalInterface.GetAllRegisterNames(); + return _gciEngine.gciExternalInterface.GetAllRegisterNames(); } } } \ No newline at end of file diff --git a/TBF/Rig/BridgeComponents/GciBridge/GciBridgeCfgCtrl.Designer.cs b/TBF/Rig/BridgeComponents/GciBridge/GciBridgeCfgCtrl.Designer.cs index 57ba790d1..d6781e0ae 100644 --- a/TBF/Rig/BridgeComponents/GciBridge/GciBridgeCfgCtrl.Designer.cs +++ b/TBF/Rig/BridgeComponents/GciBridge/GciBridgeCfgCtrl.Designer.cs @@ -31,18 +31,18 @@ this.classNameLabel = new System.Windows.Forms.Label(); this.nameLabel = new System.Windows.Forms.Label(); this.nameTextBox = new System.Windows.Forms.TextBox(); + this.groupBox1 = new System.Windows.Forms.GroupBox(); + this.showGciBridgeGUIButton = new System.Windows.Forms.Button(); + this.showGciGuiButton = new System.Windows.Forms.Button(); this.readerNameLabel = new System.Windows.Forms.Label(); this.readerNameComboBox = new System.Windows.Forms.ComboBox(); this.writerNameLabel = new System.Windows.Forms.Label(); this.writerNameComboBox = new System.Windows.Forms.ComboBox(); + this.externalTypeNameTextBox = new System.Windows.Forms.TextBox(); + this.externalTypeNameLabel = new System.Windows.Forms.Label(); this.enableGuiCheckBox = new System.Windows.Forms.CheckBox(); this.enableExternalCheckBox = new System.Windows.Forms.CheckBox(); this.showGuiOnInitializeCheckBox = new System.Windows.Forms.CheckBox(); - this.externalTypeNameLabel = new System.Windows.Forms.Label(); - this.externalTypeNameTextBox = new System.Windows.Forms.TextBox(); - this.groupBox1 = new System.Windows.Forms.GroupBox(); - this.showGciBridgeGUIButton = new System.Windows.Forms.Button(); - this.showGciGuiButton = new System.Windows.Forms.Button(); this.groupBox1.SuspendLayout(); this.SuspendLayout(); // @@ -72,6 +72,37 @@ this.nameTextBox.Size = new System.Drawing.Size(290, 20); this.nameTextBox.TabIndex = 2; // + // groupBox1 + // + this.groupBox1.Controls.Add(this.showGciBridgeGUIButton); + this.groupBox1.Controls.Add(this.showGciGuiButton); + this.groupBox1.Location = new System.Drawing.Point(31, 241); + this.groupBox1.Name = "groupBox1"; + this.groupBox1.Size = new System.Drawing.Size(573, 60); + this.groupBox1.TabIndex = 12; + this.groupBox1.TabStop = false; + this.groupBox1.Text = "Diagnostic GUI"; + // + // showGciBridgeGUIButton + // + this.showGciBridgeGUIButton.Location = new System.Drawing.Point(311, 19); + this.showGciBridgeGUIButton.Name = "showGciBridgeGUIButton"; + this.showGciBridgeGUIButton.Size = new System.Drawing.Size(134, 28); + this.showGciBridgeGUIButton.TabIndex = 2; + this.showGciBridgeGUIButton.Text = "Show GciBridge GUI"; + this.showGciBridgeGUIButton.UseVisualStyleBackColor = true; + this.showGciBridgeGUIButton.Click += new System.EventHandler(this.showGciBridgeGUIButton_Click); + // + // showGciGuiButton + // + this.showGciGuiButton.Location = new System.Drawing.Point(451, 19); + this.showGciGuiButton.Name = "showGciGuiButton"; + this.showGciGuiButton.Size = new System.Drawing.Size(107, 28); + this.showGciGuiButton.TabIndex = 1; + this.showGciGuiButton.Text = "Show GCI GUI"; + this.showGciGuiButton.UseVisualStyleBackColor = true; + this.showGciGuiButton.Click += new System.EventHandler(this.showGuiButton_Click); + // // readerNameLabel // this.readerNameLabel.AutoSize = true; @@ -108,6 +139,23 @@ this.writerNameComboBox.Size = new System.Drawing.Size(465, 21); this.writerNameComboBox.TabIndex = 6; // + // externalTypeNameTextBox + // + this.externalTypeNameTextBox.Enabled = false; + this.externalTypeNameTextBox.Location = new System.Drawing.Point(139, 202); + this.externalTypeNameTextBox.Name = "externalTypeNameTextBox"; + this.externalTypeNameTextBox.Size = new System.Drawing.Size(290, 20); + this.externalTypeNameTextBox.TabIndex = 11; + // + // externalTypeNameLabel + // + this.externalTypeNameLabel.AutoSize = true; + this.externalTypeNameLabel.Location = new System.Drawing.Point(28, 205); + this.externalTypeNameLabel.Name = "externalTypeNameLabel"; + this.externalTypeNameLabel.Size = new System.Drawing.Size(105, 13); + this.externalTypeNameLabel.TabIndex = 10; + this.externalTypeNameLabel.Text = "External type / name"; + // // enableGuiCheckBox // this.enableGuiCheckBox.AutoSize = true; @@ -141,54 +189,6 @@ this.showGuiOnInitializeCheckBox.Text = "Show GUI on initialize"; this.showGuiOnInitializeCheckBox.UseVisualStyleBackColor = true; // - // externalTypeNameLabel - // - this.externalTypeNameLabel.AutoSize = true; - this.externalTypeNameLabel.Location = new System.Drawing.Point(28, 205); - this.externalTypeNameLabel.Name = "externalTypeNameLabel"; - this.externalTypeNameLabel.Size = new System.Drawing.Size(105, 13); - this.externalTypeNameLabel.TabIndex = 10; - this.externalTypeNameLabel.Text = "External type / name"; - // - // externalTypeNameTextBox - // - this.externalTypeNameTextBox.Enabled = false; - this.externalTypeNameTextBox.Location = new System.Drawing.Point(139, 202); - this.externalTypeNameTextBox.Name = "externalTypeNameTextBox"; - this.externalTypeNameTextBox.Size = new System.Drawing.Size(290, 20); - this.externalTypeNameTextBox.TabIndex = 11; - // - // groupBox1 - // - this.groupBox1.Controls.Add(this.showGciBridgeGUIButton); - this.groupBox1.Controls.Add(this.showGciGuiButton); - this.groupBox1.Location = new System.Drawing.Point(31, 241); - this.groupBox1.Name = "groupBox1"; - this.groupBox1.Size = new System.Drawing.Size(573, 60); - this.groupBox1.TabIndex = 12; - this.groupBox1.TabStop = false; - this.groupBox1.Text = "Diagnostic GUI"; - // - // showGciBridgeGUIButton - // - this.showGciBridgeGUIButton.Location = new System.Drawing.Point(311, 19); - this.showGciBridgeGUIButton.Name = "showGciBridgeGUIButton"; - this.showGciBridgeGUIButton.Size = new System.Drawing.Size(134, 28); - this.showGciBridgeGUIButton.TabIndex = 2; - this.showGciBridgeGUIButton.Text = "Show GciBridge GUI"; - this.showGciBridgeGUIButton.UseVisualStyleBackColor = true; - this.showGciBridgeGUIButton.Click += new System.EventHandler(this.showGciBridgeGUIButton_Click); - // - // showGciGuiButton - // - this.showGciGuiButton.Location = new System.Drawing.Point(451, 19); - this.showGciGuiButton.Name = "showGciGuiButton"; - this.showGciGuiButton.Size = new System.Drawing.Size(107, 28); - this.showGciGuiButton.TabIndex = 1; - this.showGciGuiButton.Text = "Show GCI GUI"; - this.showGciGuiButton.UseVisualStyleBackColor = true; - this.showGciGuiButton.Click += new System.EventHandler(this.showGuiButton_Click); - // // GciBridgeCfgCtrl // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); @@ -220,17 +220,17 @@ private System.Windows.Forms.Label classNameLabel; private System.Windows.Forms.Label nameLabel; private System.Windows.Forms.TextBox nameTextBox; + private System.Windows.Forms.GroupBox groupBox1; + private System.Windows.Forms.Button showGciGuiButton; + private System.Windows.Forms.Button showGciBridgeGUIButton; private System.Windows.Forms.Label readerNameLabel; private System.Windows.Forms.ComboBox readerNameComboBox; private System.Windows.Forms.Label writerNameLabel; private System.Windows.Forms.ComboBox writerNameComboBox; + private System.Windows.Forms.TextBox externalTypeNameTextBox; + private System.Windows.Forms.Label externalTypeNameLabel; private System.Windows.Forms.CheckBox enableGuiCheckBox; private System.Windows.Forms.CheckBox enableExternalCheckBox; private System.Windows.Forms.CheckBox showGuiOnInitializeCheckBox; - private System.Windows.Forms.Label externalTypeNameLabel; - private System.Windows.Forms.TextBox externalTypeNameTextBox; - private System.Windows.Forms.GroupBox groupBox1; - private System.Windows.Forms.Button showGciGuiButton; - private System.Windows.Forms.Button showGciBridgeGUIButton; } } \ No newline at end of file diff --git a/TBF/Rig/BridgeComponents/GciBridge/Interfaces/PublicModels.cs b/TBF/Rig/BridgeComponents/GciBridge/Interfaces/PublicModels.cs index 2baa4c894..f3cf2a6dd 100644 --- a/TBF/Rig/BridgeComponents/GciBridge/Interfaces/PublicModels.cs +++ b/TBF/Rig/BridgeComponents/GciBridge/Interfaces/PublicModels.cs @@ -95,6 +95,36 @@ namespace TBF.Rig.BridgeComponents.GciBridge.Interfaces } } + /// + /// Represents result of pre-adjustment calibration + /// parameter lookup. + /// + /// Parameters are returned as key/value pairs: + /// + /// Key: + /// Calibration parameter name + /// + /// Value: + /// Calibration parameter value + /// + public class UdsPreAdjustmentCalibrationParamsResult + { + public bool Success { get; set; } + public int MeterSize { get; set; } + public Dictionary CalibrationParams { get; set; } + public string Message { get; set; } + + public override string ToString() + { + if (CalibrationParams == null || CalibrationParams.Count == 0) + { + return $"Success={Success}, MeterSize={MeterSize}, Message={Message}"; + } + + return $"Success={Success}, MeterSize={MeterSize}, Params={CalibrationParams.Count}, Message={Message}"; + } + } + public class GciFullLoginResult { public int SlotId { get; set; } diff --git a/TBF/Rig/BridgeComponents/GciBridge/UI/Debug/MeterGridManager.cs b/TBF/Rig/BridgeComponents/GciBridge/UI/Debug/MeterGridManager.cs new file mode 100644 index 000000000..451ab33fb --- /dev/null +++ b/TBF/Rig/BridgeComponents/GciBridge/UI/Debug/MeterGridManager.cs @@ -0,0 +1,481 @@ +using Common; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Windows.Forms; +using PublicModels = GenesisCordonelInterface.API.PublicModels; + +namespace TBF.Rig.BridgeComponents.GciBridge.UI.Grid +{ + public class MeterGridManager + { + private readonly DataGridView grid; + + public MeterGridManager(DataGridView grid) + { + this.grid = grid ?? throw new ArgumentNullException(nameof(grid)); + EnableDoubleBuffering(grid); + } + + public void Init(List comPorts) + { + grid.SuspendLayout(); + + try + { + grid.AutoGenerateColumns = false; + grid.Columns.Clear(); + + grid.AllowUserToAddRows = false; + grid.AllowUserToDeleteRows = false; + grid.RowHeadersVisible = true; + + CreateColumns(comPorts); + ConfigureReadOnlyColumns(); + ConfigureSelection(); + } + finally + { + grid.ResumeLayout(); + } + + grid.Focus(); + grid.ClipboardCopyMode = DataGridViewClipboardCopyMode.EnableWithoutHeaderText; + } + + private void CreateColumns(List comPorts) + { + var configs = MeterGridConfigProvider + .GetDefault() + .OrderBy(x => x.DisplayIndex); + + foreach (var config in configs) + { + DataGridViewColumn column; + + switch (config.ColumnType) + { + case MeterGridConfigProvider.MeterGridColumnType.CheckBox: + column = new DataGridViewCheckBoxColumn(); + break; + + default: + column = new DataGridViewTextBoxColumn(); + break; + } + + column.Name = config.Name; + column.HeaderText = config.HeaderText; + column.Width = config.Width; + column.ReadOnly = config.ReadOnly; + column.DisplayIndex = config.DisplayIndex; + + grid.Columns.Add(column); + } + + grid.Columns.Add(CreateComPortColumn("RequestPort", "RequestPort", comPorts)); + grid.Columns.Add(CreateRequestPortTypeColumn()); + grid.Columns.Add(CreateComPortColumn("StreamingPort", "StreamingPort", comPorts)); + + grid.Columns.Add(CreateButtonColumn("DetectRequest", "DetectRequest", "...")); + grid.Columns.Add(CreateButtonColumn("DetectStreaming", "DetectStreaming", "...")); + } + + private void ConfigureReadOnlyColumns() + { + foreach (DataGridViewColumn col in grid.Columns) + { + col.ReadOnly = + col.Name != "Selected" && + col.Name != "RequestPort" && + col.Name != "RequestPortType" && + col.Name != "StreamingPort" && + col.Name != "DetectRequest" && + col.Name != "DetectStreaming"; + } + } + + private void ConfigureSelection() + { + grid.MultiSelect = true; + grid.SelectionMode = DataGridViewSelectionMode.FullRowSelect; + + grid.CellContentClick -= Grid_CellContentClick; + grid.CellContentClick += Grid_CellContentClick; + + grid.CurrentCellDirtyStateChanged -= Grid_CurrentCellDirtyStateChanged; + grid.CurrentCellDirtyStateChanged += Grid_CurrentCellDirtyStateChanged; + } + + public void UpdateComPortItems(List comPorts) + { + UpdateComPortColumnItems("RequestPort", comPorts); + UpdateComPortColumnItems("StreamingPort", comPorts); + } + + public void Update(List meters) + { + grid.SuspendLayout(); + + try + { + foreach (var meter in meters) + { + var row = FindOrCreateRow(meter.Slot); + + SetCell(row, "Slot", meter.Slot); + SetCell(row, "Selected", meter.Selected); + SetCell(row, "PcbId", meter.PcbId); + SetCell(row, "IsConnected", meter.IsConnected); + SetCell(row, "IsLoggedOn", meter.IsLoggedOn); + SetCell(row, "RequestPort", meter.RequestPort); + SetCell(row, "RequestPortType", NormalizeRequestPortType(meter.RequestPortType)); + SetCell(row, "StreamingPort", meter.StreamingPort); + SetCell(row, "FwVersion", meter.FwVersion); + SetCell(row, "InterfaceVersion", meter.InterfaceVersion); + } + } + finally + { + grid.ResumeLayout(); + } + } + + public void UpdateSlots(List slots) + { + grid.SuspendLayout(); + + try + { + foreach (var slot in slots) + { + var row = FindOrCreateRow(slot.SlotId); + + SetCell(row, "Slot", slot.SlotId); + SetCell(row, "PcbId", slot.PcbId); + SetCell(row, "RequestPort", slot.RequestPort == null ? "" : slot.RequestPort.PortName); + SetCell(row, "RequestPortType", MapRequestPortTypeBack(slot.RequestPort == null ? null : slot.RequestPort.Type)); + SetCell(row, "StreamingPort", slot.StreamingPort == null ? "" : slot.StreamingPort.PortName); + SetCell(row, "IsConnected", false); + SetCell(row, "IsLoggedOn", false); + SetCell(row, "FwVersion", ""); + SetCell(row, "InterfaceVersion", ""); + } + } + finally + { + grid.ResumeLayout(); + } + } + + public void AddEmptySlotRow() + { + AddSlotRow(GetNextSlotId()); + } + + public void AddSlotRow() + { + AddSlotRow(GetNextSlotId()); + } + + public void AddSlotRow(int slotId) + { + if (ContainsSlot(slotId)) + throw new Exception($"Slot {slotId} already exists."); + + int idx = grid.Rows.Add(); + var row = grid.Rows[idx]; + + SetCell(row, "Slot", slotId); + SetCell(row, "Selected", false); + SetCell(row, "RequestPort", ""); + SetCell(row, "RequestPortType", "IRDA"); + SetCell(row, "StreamingPort", ""); + SetCell(row, "PcbId", ""); + SetCell(row, "IsConnected", false); + SetCell(row, "IsLoggedOn", false); + SetCell(row, "FwVersion", ""); + SetCell(row, "InterfaceVersion", ""); + } + + public List GetGridData() + { + var list = new List(); + + foreach (DataGridViewRow row in grid.Rows) + { + if (row.IsNewRow) + continue; + + if (row.Cells["Slot"].Value == null) + continue; + + list.Add(new PublicModels.MeterBatchDebugStatus + { + Slot = Convert.ToInt32(row.Cells["Slot"].Value), + Selected = GetBool(row, "Selected"), + PcbId = GetString(row, "PcbId"), + IsConnected = GetBool(row, "IsConnected"), + IsLoggedOn = GetBool(row, "IsLoggedOn"), + RequestPort = GetString(row, "RequestPort"), + RequestPortType = NormalizeRequestPortType(GetString(row, "RequestPortType")), + StreamingPort = GetString(row, "StreamingPort"), + FwVersion = GetString(row, "FwVersion"), + InterfaceVersion = GetString(row, "InterfaceVersion") + }); + } + + return list; + } + + public List GetSelectedGridData() + { + return GetGridData() + .Where(x => x.Selected) + .ToList(); + } + + public int GetSlotFromRow(int rowIndex) + { + if (rowIndex < 0) + throw new ArgumentOutOfRangeException(nameof(rowIndex)); + + return Convert.ToInt32(grid.Rows[rowIndex].Cells["Slot"].Value); + } + + public string GetColumnName(int columnIndex) + { + return grid.Columns[columnIndex].Name; + } + + public void ClearSlots() + { + grid.Rows.Clear(); + } + + public int GetNextSlotId() + { + var existingSlots = grid.Rows + .Cast() + .Where(r => !r.IsNewRow) + .Where(r => r.Cells["Slot"].Value != null) + .Select(r => Convert.ToInt32(r.Cells["Slot"].Value)) + .ToList(); + + if (existingSlots.Count == 0) + return 1; + + return existingSlots.Max() + 1; + } + + private bool ContainsSlot(int slotId) + { + return grid.Rows + .Cast() + .Any(r => + !r.IsNewRow && + r.Cells["Slot"].Value != null && + Convert.ToInt32(r.Cells["Slot"].Value) == slotId); + } + + private DataGridViewRow FindOrCreateRow(int slot) + { + foreach (DataGridViewRow row in grid.Rows) + { + if (!row.IsNewRow && + row.Cells["Slot"].Value != null && + Convert.ToInt32(row.Cells["Slot"].Value) == slot) + { + return row; + } + } + + int idx = grid.Rows.Add(); + var newRow = grid.Rows[idx]; + newRow.Cells["Slot"].Value = slot; + return newRow; + } + + private void SetCell(DataGridViewRow row, string colName, object value) + { + if (!grid.Columns.Contains(colName)) + return; + + if (value == null) + value = ""; + + if (colName == "RequestPortType") + value = NormalizeRequestPortType(Convert.ToString(value)); + + var cell = row.Cells[colName]; + + if (!Equals(cell.Value, value)) + cell.Value = value; + } + + private string GetString(DataGridViewRow row, string colName) + { + if (!grid.Columns.Contains(colName)) + return ""; + + return Convert.ToString(row.Cells[colName].Value); + } + + private bool GetBool(DataGridViewRow row, string colName) + { + if (!grid.Columns.Contains(colName)) + return false; + + if (row.Cells[colName].Value == null) + return false; + + return Convert.ToBoolean(row.Cells[colName].Value); + } + + private DataGridViewComboBoxColumn CreateComPortColumn( + string name, + string headerText, + List comPorts) + { + return new DataGridViewComboBoxColumn + { + Name = name, + HeaderText = headerText, + DataSource = new List(comPorts ?? new List()), + FlatStyle = FlatStyle.Flat, + DisplayStyle = DataGridViewComboBoxDisplayStyle.DropDownButton + }; + } + + private DataGridViewComboBoxColumn CreateRequestPortTypeColumn() + { + return new DataGridViewComboBoxColumn + { + Name = "RequestPortType", + HeaderText = "RequestPortType", + DataSource = new List { "", "IRDA", "UART", "RFID" }, + FlatStyle = FlatStyle.Flat, + DisplayStyle = DataGridViewComboBoxDisplayStyle.DropDownButton + }; + } + + private DataGridViewButtonColumn CreateButtonColumn( + string name, + string headerText, + string text) + { + return new DataGridViewButtonColumn + { + Name = name, + HeaderText = headerText, + Text = text, + UseColumnTextForButtonValue = true + }; + } + + private void UpdateComPortColumnItems(string columnName, List comPorts) + { + var col = grid.Columns[columnName] as DataGridViewComboBoxColumn; + if (col == null) + return; + + col.DataSource = null; + col.DataSource = new List(comPorts ?? new List()); + } + + private string NormalizeRequestPortType(string value) + { + if (string.IsNullOrWhiteSpace(value)) + return ""; + + string normalized = value.Trim(); + + if (normalized.Equals("RFID", StringComparison.OrdinalIgnoreCase) || + normalized.IndexOf("RfidSerialPort", StringComparison.OrdinalIgnoreCase) >= 0) + return "RFID"; + + if (normalized.Equals("UART", StringComparison.OrdinalIgnoreCase) || + normalized.IndexOf("UartSerialPort", StringComparison.OrdinalIgnoreCase) >= 0) + return "UART"; + + if (normalized.Equals("IRDA", StringComparison.OrdinalIgnoreCase) || + normalized.Equals("IrDA", StringComparison.OrdinalIgnoreCase) || + normalized.IndexOf("IrdaSerialPort", StringComparison.OrdinalIgnoreCase) >= 0) + return "IRDA"; + + return ""; + } + + public bool RemoveSlot(int slotId) + { + grid.SuspendLayout(); + + try + { + foreach (DataGridViewRow row in grid.Rows) + { + if (row.IsNewRow) + continue; + + if (row.Cells["Slot"].Value == null) + continue; + + if (Convert.ToInt32(row.Cells["Slot"].Value) == slotId) + { + grid.Rows.Remove(row); + return true; + } + } + + return false; + } + finally + { + grid.ResumeLayout(); + } + } + + private string MapRequestPortTypeBack(string fullType) + { + return NormalizeRequestPortType(fullType); + } + + private void EnableDoubleBuffering(DataGridView dgv) + { + typeof(DataGridView) + .GetProperty( + "DoubleBuffered", + BindingFlags.Instance | BindingFlags.NonPublic) + ?.SetValue(dgv, true, null); + } + + private void Grid_CurrentCellDirtyStateChanged(object sender, EventArgs e) + { + if (grid.IsCurrentCellDirty) + { + grid.CommitEdit(DataGridViewDataErrorContexts.Commit); + } + } + + private void Grid_CellContentClick(object sender, DataGridViewCellEventArgs e) + { + if (e.RowIndex < 0) + return; + + if (grid.Columns[e.ColumnIndex].Name != "Selected") + return; + + bool clickedValue = Convert.ToBoolean( + grid.Rows[e.RowIndex].Cells["Selected"].Value); + + foreach (DataGridViewRow row in grid.SelectedRows) + { + if (row.Index == e.RowIndex) + continue; + + row.Cells["Selected"].Value = clickedValue; + } + } + } +} \ No newline at end of file diff --git a/TBF/Rig/BridgeComponents/GciBridge/UI/MainView.Designer.cs b/TBF/Rig/BridgeComponents/GciBridge/UI/MainView.Designer.cs index 86d9058c0..190f7bce2 100644 --- a/TBF/Rig/BridgeComponents/GciBridge/UI/MainView.Designer.cs +++ b/TBF/Rig/BridgeComponents/GciBridge/UI/MainView.Designer.cs @@ -316,7 +316,7 @@ // this.splitWorkArea.Panel2.Controls.Add(this.rtbMainLog); this.splitWorkArea.Size = new System.Drawing.Size(700, 320); - this.splitWorkArea.SplitterDistance = 233; + this.splitWorkArea.SplitterDistance = 320; this.splitWorkArea.SplitterWidth = 6; this.splitWorkArea.TabIndex = 0; // @@ -326,7 +326,7 @@ this.pnlGciViewHost.Dock = System.Windows.Forms.DockStyle.Fill; this.pnlGciViewHost.Location = new System.Drawing.Point(0, 0); this.pnlGciViewHost.Name = "pnlGciViewHost"; - this.pnlGciViewHost.Size = new System.Drawing.Size(233, 320); + this.pnlGciViewHost.Size = new System.Drawing.Size(320, 320); this.pnlGciViewHost.TabIndex = 0; // // rtbMainLog @@ -336,7 +336,7 @@ this.rtbMainLog.Location = new System.Drawing.Point(0, 0); this.rtbMainLog.Name = "rtbMainLog"; this.rtbMainLog.ReadOnly = true; - this.rtbMainLog.Size = new System.Drawing.Size(461, 320); + this.rtbMainLog.Size = new System.Drawing.Size(374, 320); this.rtbMainLog.TabIndex = 0; this.rtbMainLog.Text = ""; // diff --git a/TBF/Rig/BridgeComponents/GciBridge/UI/MainView.cs b/TBF/Rig/BridgeComponents/GciBridge/UI/MainView.cs index 24a978409..75f69e984 100644 --- a/TBF/Rig/BridgeComponents/GciBridge/UI/MainView.cs +++ b/TBF/Rig/BridgeComponents/GciBridge/UI/MainView.cs @@ -55,7 +55,7 @@ namespace TBF.Rig.BridgeComponents.GciBridge.UI _mainForm = mainform; _bridge = bridge; _gciApi = bridge.gciExternalInterface; - _laatzenApi = _bridge.gciExternalInterface._innerMeterAPI; + _laatzenApi = bridge._gciEngine.gciExternalInterface._innerMeterAPI; InitializeComponent(); InitializeDebugPanels(); //InitializeWorkerDebugPanel(); diff --git a/TBF/Rig/BridgeComponents/GciBridge/UI/StaraTuraAPI_GciBridge/CombinedActionsView.cs b/TBF/Rig/BridgeComponents/GciBridge/UI/StaraTuraAPI_GciBridge/CombinedActionsView.cs index 45f95bb5a..ce7e582fa 100644 --- a/TBF/Rig/BridgeComponents/GciBridge/UI/StaraTuraAPI_GciBridge/CombinedActionsView.cs +++ b/TBF/Rig/BridgeComponents/GciBridge/UI/StaraTuraAPI_GciBridge/CombinedActionsView.cs @@ -90,7 +90,7 @@ namespace TBF.Rig.BridgeComponents.GciBridge.UI.StaraTuraAPI_GciBridge int slot = item.Key; string pcbId = item.Value; - //var result = await _bridge.GetPasswordAsync(pcbId, token); + //var result = await _bridge.ReadMeterLoginPasswordAsync(pcbId, token); var result = await _bridge.GetPasswordWithRetryAsync(pcbId, token); LogResult($"UDSR/GetPassword slot {slot}, PCB={pcbId}", result); 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 42016c8c8..e5a4f3b2f 100644 --- a/TBF/Rig/BridgeComponents/GciBridge/UI/StaraTuraAPI_GciBridge/PreadjustmentActionsView.Designer.cs +++ b/TBF/Rig/BridgeComponents/GciBridge/UI/StaraTuraAPI_GciBridge/PreadjustmentActionsView.Designer.cs @@ -24,6 +24,11 @@ private void InitializeComponent() { this.grpSlots = new System.Windows.Forms.GroupBox(); + this.pushTestBenchTempButton = new System.Windows.Forms.Button(); + this.pushedTestBenchTempTextBox = new System.Windows.Forms.TextBox(); + this.label8 = new System.Windows.Forms.Label(); + this.cb_Metersize = new System.Windows.Forms.ComboBox(); + this.l_SettingsPreparationMetersize = new System.Windows.Forms.Label(); this.label7 = new System.Windows.Forms.Label(); this.label6 = new System.Windows.Forms.Label(); this.label5 = new System.Windows.Forms.Label(); @@ -40,13 +45,14 @@ this.amplitudeTestActionButton = new System.Windows.Forms.Button(); this.btnCancel = new System.Windows.Forms.Button(); this.txtLog = new System.Windows.Forms.TextBox(); - this.cb_Metersize = new System.Windows.Forms.ComboBox(); - this.l_SettingsPreparationMetersize = new System.Windows.Forms.Label(); this.grpSlots.SuspendLayout(); this.SuspendLayout(); // // grpSlots // + this.grpSlots.Controls.Add(this.pushTestBenchTempButton); + this.grpSlots.Controls.Add(this.pushedTestBenchTempTextBox); + this.grpSlots.Controls.Add(this.label8); this.grpSlots.Controls.Add(this.cb_Metersize); this.grpSlots.Controls.Add(this.l_SettingsPreparationMetersize); this.grpSlots.Controls.Add(this.label7); @@ -71,6 +77,50 @@ this.grpSlots.Text = "Slots by selection in the table"; this.grpSlots.Enter += new System.EventHandler(this.grpSlots_Enter); // + // pushTestBenchTempButton + // + this.pushTestBenchTempButton.Location = new System.Drawing.Point(593, 186); + this.pushTestBenchTempButton.Name = "pushTestBenchTempButton"; + this.pushTestBenchTempButton.Size = new System.Drawing.Size(81, 21); + this.pushTestBenchTempButton.TabIndex = 121; + this.pushTestBenchTempButton.Text = "Push temp"; + this.pushTestBenchTempButton.Click += new System.EventHandler(this.pushTestBenchTempButton_Click); + // + // pushedTestBenchTempTextBox + // + this.pushedTestBenchTempTextBox.Location = new System.Drawing.Point(550, 186); + this.pushedTestBenchTempTextBox.Name = "pushedTestBenchTempTextBox"; + this.pushedTestBenchTempTextBox.Size = new System.Drawing.Size(37, 20); + this.pushedTestBenchTempTextBox.TabIndex = 120; + // + // label8 + // + this.label8.AutoSize = true; + this.label8.Location = new System.Drawing.Point(440, 189); + this.label8.Margin = new System.Windows.Forms.Padding(2, 0, 2, 0); + this.label8.Name = "label8"; + this.label8.Size = new System.Drawing.Size(105, 13); + this.label8.TabIndex = 118; + this.label8.Text = "Pushed temperature:"; + // + // cb_Metersize + // + this.cb_Metersize.FormattingEnabled = true; + this.cb_Metersize.Location = new System.Drawing.Point(74, 30); + this.cb_Metersize.Name = "cb_Metersize"; + this.cb_Metersize.Size = new System.Drawing.Size(73, 21); + this.cb_Metersize.TabIndex = 117; + // + // l_SettingsPreparationMetersize + // + this.l_SettingsPreparationMetersize.AutoSize = true; + this.l_SettingsPreparationMetersize.Location = new System.Drawing.Point(14, 36); + this.l_SettingsPreparationMetersize.Margin = new System.Windows.Forms.Padding(2, 0, 2, 0); + this.l_SettingsPreparationMetersize.Name = "l_SettingsPreparationMetersize"; + this.l_SettingsPreparationMetersize.Size = new System.Drawing.Size(55, 13); + this.l_SettingsPreparationMetersize.TabIndex = 116; + this.l_SettingsPreparationMetersize.Text = "Metersize:"; + // // label7 // this.label7.AutoSize = true; @@ -157,6 +207,7 @@ this.completionActionButton.Size = new System.Drawing.Size(150, 28); this.completionActionButton.TabIndex = 3; this.completionActionButton.Text = "Completition"; + this.completionActionButton.Click += new System.EventHandler(this.completionActionButton_Click); // // offsetTestActionButton // @@ -165,6 +216,7 @@ this.offsetTestActionButton.Size = new System.Drawing.Size(150, 28); this.offsetTestActionButton.TabIndex = 5; this.offsetTestActionButton.Text = "Offset test"; + this.offsetTestActionButton.Click += new System.EventHandler(this.offsetTestActionButton_Click); // // preparationActionButton // @@ -191,7 +243,7 @@ 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); + this.temperatureCalibrationActionButton.Click += new System.EventHandler(this.temperatureCalibrationActionButton_Click); // // amplitudeTestActionButton // @@ -200,6 +252,7 @@ this.amplitudeTestActionButton.Size = new System.Drawing.Size(150, 28); this.amplitudeTestActionButton.TabIndex = 18; this.amplitudeTestActionButton.Text = "Amplitude test"; + this.amplitudeTestActionButton.Click += new System.EventHandler(this.amplitudeTestActionButton_Click); // // btnCancel // @@ -225,24 +278,6 @@ this.txtLog.TabIndex = 5; this.txtLog.WordWrap = false; // - // cb_Metersize - // - this.cb_Metersize.FormattingEnabled = true; - this.cb_Metersize.Location = new System.Drawing.Point(74, 30); - this.cb_Metersize.Name = "cb_Metersize"; - this.cb_Metersize.Size = new System.Drawing.Size(73, 21); - this.cb_Metersize.TabIndex = 117; - // - // l_SettingsPreparationMetersize - // - this.l_SettingsPreparationMetersize.AutoSize = true; - this.l_SettingsPreparationMetersize.Location = new System.Drawing.Point(14, 36); - this.l_SettingsPreparationMetersize.Margin = new System.Windows.Forms.Padding(2, 0, 2, 0); - this.l_SettingsPreparationMetersize.Name = "l_SettingsPreparationMetersize"; - this.l_SettingsPreparationMetersize.Size = new System.Drawing.Size(55, 13); - this.l_SettingsPreparationMetersize.TabIndex = 116; - this.l_SettingsPreparationMetersize.Text = "Metersize:"; - // // PreadjustmentActionsView // this.BackColor = System.Drawing.SystemColors.Control; @@ -271,5 +306,8 @@ private System.Windows.Forms.Label label6; private System.Windows.Forms.ComboBox cb_Metersize; private System.Windows.Forms.Label l_SettingsPreparationMetersize; + private System.Windows.Forms.Button pushTestBenchTempButton; + private System.Windows.Forms.TextBox pushedTestBenchTempTextBox; + private System.Windows.Forms.Label label8; } } \ 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 395f3f81e..9a3bc1bbb 100644 --- a/TBF/Rig/BridgeComponents/GciBridge/UI/StaraTuraAPI_GciBridge/PreadjustmentActionsView.cs +++ b/TBF/Rig/BridgeComponents/GciBridge/UI/StaraTuraAPI_GciBridge/PreadjustmentActionsView.cs @@ -1,13 +1,17 @@ -using CordonelPreadjustmentUi; +using Common; +using CordonelPreadjustmentUi; using CordonelPreadjustmentUi.Processes.Itinerary; using GenesisCordonelInterface.API; using GenesisCordonelInterface.UI; using System; using System.Collections.Generic; +using System.Drawing; +using System.Globalization; using System.Linq; using System.Threading; using System.Threading.Tasks; using System.Windows.Forms; +using TBF.UiBridge; using Xylem.Common.Hardware.WaterMeter.WaterMeterCore; using Xylem.Common.Logic.ProductionOrderCore.OrderData; using Xylem.Common.Ui.CordonelPreadjustmentUi; @@ -17,6 +21,8 @@ using GciPublicModels = GenesisCordonelInterface.API.PublicModels; namespace TBF.Rig.BridgeComponents.GciBridge.UI.StaraTuraAPI_GciBridge { + + public partial class PreadjustmentActionsView : UserControl { private readonly GciBridge _bridge; @@ -25,6 +31,22 @@ namespace TBF.Rig.BridgeComponents.GciBridge.UI.StaraTuraAPI_GciBridge private readonly Action _addSlotAction; private readonly Action _saveAction; + public event EventHandler OnAbort; + + private readonly System.Windows.Forms.Timer _tempRequestTimer = new System.Windows.Forms.Timer(); + private bool _tempButtonHighlight; + + private enum PreadjustmentExecutionMode + { + AsyncSlotWorker, + DirectToProcessTasks + } + + private PreadjustmentExecutionMode _preadjustmentExecutionMode = PreadjustmentExecutionMode.DirectToProcessTasks; + + private bool UseDirectProcess => + _preadjustmentExecutionMode == PreadjustmentExecutionMode.DirectToProcessTasks; + public PreadjustmentActionsView( MainView mainview, GciBridge bridge, @@ -41,17 +63,36 @@ namespace TBF.Rig.BridgeComponents.GciBridge.UI.StaraTuraAPI_GciBridge LoadRegisterComboBoxes(); + InitGciHandlers(); + + // + cb_Metersize.Items.Clear(); foreach (MeterSize size in (MeterSize[])Enum.GetValues(typeof(MeterSize))) { cb_Metersize.Items.Add(size); } var setM = MeterSize.DN50; - if (_mainView._gciApi._innerMeterAPI._settings.MeterSize != null) - { - setM = _mainView._gciApi._innerMeterAPI._settings.MeterSize; - } cb_Metersize.SelectedItem = setM; + + // + + _tempRequestTimer.Interval = 500; + + _tempRequestTimer.Tick += (s, e) => + { + _tempButtonHighlight = !_tempButtonHighlight; + + pushTestBenchTempButton.BackColor = + _tempButtonHighlight + ? Color.Red + : SystemColors.Control; + }; + } + + private void InitGciHandlers() + { + } private void AddSlot() @@ -73,7 +114,7 @@ namespace TBF.Rig.BridgeComponents.GciBridge.UI.StaraTuraAPI_GciBridge if (slots.Count == 0) throw new Exception("No selected slots in grid."); - + return slots; } @@ -92,7 +133,8 @@ namespace TBF.Rig.BridgeComponents.GciBridge.UI.StaraTuraAPI_GciBridge private void btnCancel_Click(object sender, EventArgs e) { - _cts?.Cancel(); + OnAbort?.Invoke(null, new EventArgsMeterSuccsessfull(new List()));//stop Laatzen + _cts?.Cancel();//stop StaraTura Log("Cancel requested."); } @@ -147,21 +189,26 @@ namespace TBF.Rig.BridgeComponents.GciBridge.UI.StaraTuraAPI_GciBridge btnCancel.Enabled = busy; } - private void LogResult(string methodName, object result) + /*private void LogResult(string methodName, object result) { Log(methodName + " result:"); Log(result == null ? "" : result.ToString()); - } + }*/ - private void Log(string message) + private void Log(string msg) { txtLog.AppendText( DateTime.Now.ToString("HH:mm:ss.fff") + " " + - message + + msg + Environment.NewLine); } + private void Log(string msg, int? slot = null, string source = "APP", string PcbID = "") + { + txtLog.AppendText($"{DateTime.Now.ToString("HH:mm:ss.fff")} {source} {msg} ({PcbID}){Environment.NewLine}"); + } + private void LoadRegisterComboBoxes() { @@ -186,7 +233,7 @@ namespace TBF.Rig.BridgeComponents.GciBridge.UI.StaraTuraAPI_GciBridge return; } - ProcessProgress pp = CreatePreparationProgress(); + ProcessProgress pp = CreateProcessProgress(); List mc = CreateMeterControls(selectedSlots); var result = _bridge.Preadjustment_Initialization(pp, mc); @@ -207,8 +254,8 @@ namespace TBF.Rig.BridgeComponents.GciBridge.UI.StaraTuraAPI_GciBridge } private void detectActionButton_Click( - object sender, - EventArgs e) + object sender, + EventArgs e) { ExecuteAsync(async token => { @@ -221,13 +268,24 @@ namespace TBF.Rig.BridgeComponents.GciBridge.UI.StaraTuraAPI_GciBridge return; } - PreadjustmentDetectResult result = - await _bridge.PreAdjustment_DetectAsync(selectedSlots, token); + PreadjustmentDetectResult result; - Log( - result.Success - ? "Detect completed. " + result - : "Detect failed. " + result); + if (UseDirectProcess) + { + result = await Task.Run(() => + _bridge.PreAdjustment_DetectDirect(selectedSlots, token), + token); + } + else + { + result = await _bridge.PreAdjustment_DetectAsync( + selectedSlots, + token); + } + + Log(result.Success + ? "Detect completed. " + result + : "Detect failed. " + result); RefreshGrid(); }); @@ -239,8 +297,9 @@ namespace TBF.Rig.BridgeComponents.GciBridge.UI.StaraTuraAPI_GciBridge { ExecuteAsync(async token => { - await ExecutePreadjustmentForSelectedSlotsAsync( + await ExecutePreadjustmentActionAsync( _bridge.PreAdjustment_PreparationAsync, + _bridge.PreAdjustment_PreparationDirect, "Preparation", token); }); @@ -252,8 +311,9 @@ namespace TBF.Rig.BridgeComponents.GciBridge.UI.StaraTuraAPI_GciBridge { ExecuteAsync(async token => { - await ExecutePreadjustmentForSelectedSlotsAsync( + await ExecutePreadjustmentActionAsync( _bridge.PreAdjustment_AmplitudeTestAsync, + _bridge.PreAdjustment_AmplitudeTestDirect, "Amplitude Test", token); }); @@ -265,8 +325,9 @@ namespace TBF.Rig.BridgeComponents.GciBridge.UI.StaraTuraAPI_GciBridge { ExecuteAsync(async token => { - await ExecutePreadjustmentForSelectedSlotsAsync( + await ExecutePreadjustmentActionAsync( _bridge.PreAdjustment_TemperatureCalibrationAsync, + _bridge.PreAdjustment_TemperatureCalibrationDirect, "Temperature Calibration", token); }); @@ -278,8 +339,9 @@ namespace TBF.Rig.BridgeComponents.GciBridge.UI.StaraTuraAPI_GciBridge { ExecuteAsync(async token => { - await ExecutePreadjustmentForSelectedSlotsAsync( + await ExecutePreadjustmentActionAsync( _bridge.PreAdjustment_OffsetTestAsync, + _bridge.PreAdjustment_OffsetTestDirect, "Offset Test", token); }); @@ -291,27 +353,58 @@ namespace TBF.Rig.BridgeComponents.GciBridge.UI.StaraTuraAPI_GciBridge { ExecuteAsync(async token => { - await ExecutePreadjustmentForSelectedSlotsAsync( + await ExecutePreadjustmentActionAsync( _bridge.PreAdjustment_CompletionAsync, + _bridge.PreAdjustment_CompletionDirect, "Completion", token); }); } - private ProcessProgress CreatePreparationProgress() + private ProcessProgress CreateProcessProgress() { - return new ProcessProgress + ProcessProgress pp = new ProcessProgress { Setting = new PreAdjustmentSettingsContainer { - TempOnly = false, - Culture = Thread.CurrentThread.CurrentCulture, - MeterSize = (MeterSize)cb_Metersize.SelectedItem + Culture = new CultureInfo("en-US"), + MeterSize = (MeterSize)cb_Metersize.SelectedItem, + OffsetTestSettlingTime = 0 }, - IsAutomaticMode = false + IsAutomaticMode = false, }; + + pp.OnRequestTempretureSelection += RequestTempretureSelection; + pp.OnDebugMessageChanged += DebugMessageChanged; + + OnAbort += (o, args) => + { + pp.StopSequence = true; + pp.CancellationSource.Cancel(); + }; + + return pp; + + } + + private void DebugMessageChanged(object sender, EventArgsDebug e) + { + BeginInvoke(new Action(() => + { + Log(e.Value, e.Slot, e.Source, e.PcbId); + })); + } + + private void RequestTempretureSelection(object sender, EventArgs e) + { + BeginInvoke(new Action(() => + { + Log("Temperature requesting, please set actual value"); + + _tempRequestTimer.Start(); + })); } private List CreateMeterControls(IEnumerable slots) @@ -332,79 +425,13 @@ namespace TBF.Rig.BridgeComponents.GciBridge.UI.StaraTuraAPI_GciBridge return controls; } - private PreAdjustmentSettingsContainer CreatePreAdjustmentSettings(IEnumerable slots) + + private void pushTestBenchTempButton_Click(object sender, EventArgs e) { - var settings = - new PreAdjustmentSettingsContainer(); + _bridge.PreAdjustment_PushTemperature(Convert.ToDouble(pushedTestBenchTempTextBox.Text)); - 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(); - });*/ + _tempRequestTimer.Stop(); + pushTestBenchTempButton.BackColor = SystemColors.Control; } private async Task ExecutePreadjustmentForSelectedSlotsAsync( @@ -421,9 +448,6 @@ namespace TBF.Rig.BridgeComponents.GciBridge.UI.StaraTuraAPI_GciBridge return; } - var pp = - CreatePreparationProgress(); - foreach (var selectedSlot in selectedSlots) { PreAdjustmentProcessResult result = @@ -441,5 +465,31 @@ namespace TBF.Rig.BridgeComponents.GciBridge.UI.StaraTuraAPI_GciBridge RefreshGrid(); } + + private async Task ExecutePreadjustmentActionAsync( + Func> asyncAction, + Func directAction, + string processName, + CancellationToken token) + { + if (UseDirectProcess) + { + PreAdjustmentProcessResult result = + await Task.Run(() => directAction(), token); + + Log(result.Success + ? $"{processName} completed. {result}" + : $"{processName} failed. {result}"); + + RefreshGrid(); + + return; + } + + await ExecutePreadjustmentForSelectedSlotsAsync( + asyncAction, + processName, + token); + } } } \ No newline at end of file diff --git a/TBF/Rig/BridgeComponents/GciBridge/UI/StaraTuraAPI_GciBridge/UniDataSorageActionsView.Designer.cs b/TBF/Rig/BridgeComponents/GciBridge/UI/StaraTuraAPI_GciBridge/UniDataSorageActionsView.Designer.cs index c893830fd..41c3ca1ee 100644 --- a/TBF/Rig/BridgeComponents/GciBridge/UI/StaraTuraAPI_GciBridge/UniDataSorageActionsView.Designer.cs +++ b/TBF/Rig/BridgeComponents/GciBridge/UI/StaraTuraAPI_GciBridge/UniDataSorageActionsView.Designer.cs @@ -21,31 +21,53 @@ 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.getCalibrationParamsButton = new System.Windows.Forms.Button(); + this.label1 = new System.Windows.Forms.Label(); + this.calibrationParamsTextBox = new System.Windows.Forms.TextBox(); this.grpStorage.SuspendLayout(); this.SuspendLayout(); // // grpStorage // + this.grpStorage.Controls.Add(this.calibrationParamsTextBox); + this.grpStorage.Controls.Add(this.label1); + this.grpStorage.Controls.Add(this.getCalibrationParamsButton); this.grpStorage.Controls.Add(this.lblPcbId); this.grpStorage.Controls.Add(this.txtPcbId); 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, 261); + this.grpStorage.Size = new System.Drawing.Size(215, 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); + this.btnGetPasswordByPcb.Location = new System.Drawing.Point(13, 48); this.btnGetPasswordByPcb.Name = "btnGetPasswordByPcb"; - this.btnGetPasswordByPcb.Size = new System.Drawing.Size(175, 28); + this.btnGetPasswordByPcb.Size = new System.Drawing.Size(196, 28); this.btnGetPasswordByPcb.TabIndex = 2; this.btnGetPasswordByPcb.Text = "Get password (by PCB)"; this.btnGetPasswordByPcb.UseVisualStyleBackColor = true; @@ -64,30 +86,40 @@ // // txtLog // - this.txtLog.Location = new System.Drawing.Point(220, 10); + this.txtLog.Location = new System.Drawing.Point(231, 10); 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(500, 340); + this.txtLog.Size = new System.Drawing.Size(489, 340); this.txtLog.TabIndex = 4; this.txtLog.WordWrap = false; // - // lblPcbId + // getCalibrationParamsButton // - 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:"; + this.getCalibrationParamsButton.Location = new System.Drawing.Point(13, 139); + this.getCalibrationParamsButton.Name = "getCalibrationParamsButton"; + this.getCalibrationParamsButton.Size = new System.Drawing.Size(196, 34); + this.getCalibrationParamsButton.TabIndex = 3; + this.getCalibrationParamsButton.Text = "Get CalibrationParams (by MeterSize)"; + this.getCalibrationParamsButton.UseVisualStyleBackColor = true; + this.getCalibrationParamsButton.Click += new System.EventHandler(this.getCalibrationParamsButton_Click); // - // txtPcbId + // label1 // - 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; + this.label1.AutoSize = true; + this.label1.Location = new System.Drawing.Point(10, 116); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(54, 13); + this.label1.TabIndex = 4; + this.label1.Text = "MeterSize"; + // + // calibrationParamsTextBox + // + this.calibrationParamsTextBox.Location = new System.Drawing.Point(65, 113); + this.calibrationParamsTextBox.Name = "calibrationParamsTextBox"; + this.calibrationParamsTextBox.Size = new System.Drawing.Size(120, 20); + this.calibrationParamsTextBox.TabIndex = 5; // // UniDataSorageActionsView // @@ -105,5 +137,8 @@ private System.Windows.Forms.Label lblPcbId; private System.Windows.Forms.TextBox txtPcbId; + private System.Windows.Forms.Label label1; + private System.Windows.Forms.Button getCalibrationParamsButton; + private System.Windows.Forms.TextBox calibrationParamsTextBox; } } \ No newline at end of file diff --git a/TBF/Rig/BridgeComponents/GciBridge/UI/StaraTuraAPI_GciBridge/UniDataSorageActionsView.cs b/TBF/Rig/BridgeComponents/GciBridge/UI/StaraTuraAPI_GciBridge/UniDataSorageActionsView.cs index da90e5da3..572435782 100644 --- a/TBF/Rig/BridgeComponents/GciBridge/UI/StaraTuraAPI_GciBridge/UniDataSorageActionsView.cs +++ b/TBF/Rig/BridgeComponents/GciBridge/UI/StaraTuraAPI_GciBridge/UniDataSorageActionsView.cs @@ -30,7 +30,7 @@ namespace TBF.Rig.BridgeComponents.GciBridge.UI.StaraTuraAPI_GciBridge var result = await _bridge.GetPasswordAsync(pcbId, token); - LogResult("GetPasswordAsync PCB=" + pcbId, result); + LogResult("ReadMeterLoginPasswordAsync PCB=" + pcbId, result); }); } @@ -100,5 +100,31 @@ namespace TBF.Rig.BridgeComponents.GciBridge.UI.StaraTuraAPI_GciBridge message + Environment.NewLine); } + + private void getCalibrationParamsButton_Click( + object sender, + EventArgs e) + { + ExecuteAsync(async token => + { + if (!int.TryParse( + calibrationParamsTextBox.Text.Trim(), + out int meterSize)) + { + throw new Exception( + "Meter size is invalid."); + } + + var result = + await _bridge.GetPreAdjustmentCalibrationParamsAsync( + meterSize, + token); + + LogResult( + "GetPreAdjustmentCalibrationParamsAsync MeterSize=" + + meterSize, + result); + }); + } } } \ No newline at end of file