tbf/GenesisCordonelTester/API/InterfaceGCIToLaatzen.cs

1056 lines
35 KiB
C#
Raw Permalink Normal View History

using Logic.ProductionToProductMapper.Cordonel;
using Newtonsoft.Json;
using NLog;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Net;
using System.Reflection;
using System.Security.Policy;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using Xylem.Common.CommonCore.Configuration;
using Xylem.Common.CommonCore.Consts;
using Xylem.Common.Hardware.Interfaces.Ports.PortCore;
using Xylem.Common.Hardware.WaterMeter.Genesis.Applications.Const;
using Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore;
using Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore.Consts;
using Xylem.Common.Hardware.WaterMeter.Genesis.Registers;
using Xylem.Common.Hardware.WaterMeter.Genesis.Registers.DataTypes;
using Xylem.Common.Hardware.WaterMeter.WaterMeterCore;
using Xylem.Common.Logic.ProductionOrderCore.TestResults;
using Xylem.Common.Logic.SoftwareAccessHelper;
using Xylem.Common.Utils.Logging;
using static Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore.GenesisMeter;
using Access = Xylem.Common.Hardware.WaterMeter.Genesis.Registers.Access;
using Register = Xylem.Common.Hardware.WaterMeter.Genesis.Registers.Register;
namespace GenesisCordonelInterface.API
{
/// <summary>
/// Provides a public API for Genesis meter operations.
///
/// This class exposes reusable functionality extracted from the original UI code
/// so it can be used from other projects within the solution.
///
/// The API is intended to gradually consolidate meter-related operations such as:
/// - port detection
/// - PCB ID reading
/// - communication setup
/// - requests and commands
/// - additional service actions
/// </summary>
/// <remarks>
/// This class should contain business logic only and should not depend on UI elements
/// such as forms, controls, MessageBox, or DataGridView.
///
/// UI-specific code should remain outside this class and call this API instead.
/// </remarks>
/// <example>
/// <code>
/// var api = new Api2();
///
/// var request = api.DetectRequestPort(3);
/// if (request.Success)
/// {
/// Console.WriteLine($"PCB ID: {request.PcbId}");
/// }
///
/// var streaming = api.DetectStreamingPort(3);
/// if (streaming.Success)
/// {
/// Console.WriteLine($"Streaming port: {streaming.PortName}");
/// }
/// </code>
/// </example>
public class InterfaceGCIToLaatzen
{
#region Declaration region
private static readonly Lazy<ILogger> Logger = new Lazy<ILogger>(() => NLogHelper.CreateOrGetLogger("GenesisCordonelInterface"));
public class regStore
{
public String PcbId;
public DateTimeOffset created;
public List<regDefValue> keyValues;
}
public class regDefValue
{
public RegisterDefinition def;
public String value;
}
private GenesisMeter _currentGenesis;
private MeterBatch _meterBatch = new MeterBatch();
private regStore _regsToStore;
private String _currentPcbId = "";
private Boolean IsBusy
{
get;
set;
}
/// <summary>
/// Gets a value indicating whether the meter is connected and logged on.
/// </summary>
public bool IsConnected
{
get
{
return _currentGenesis != null && _currentGenesis.IsLoggedOn;
}
}
#endregion
#region API - Port Detection region(extracted from FrmSetup:DgvConfig_CellContentClick)
public class PortDetectionResult
{
/// <summary>
/// Indicates whether the detection was successful.
/// </summary>
public bool Success { get; set; }
/// <summary>
/// Slot number used for the detection.
/// </summary>
public int Slot { get; set; }
/// <summary>
/// Name of the detected communication port.
/// </summary>
public string PortName { get; set; }
/// <summary>
/// PCB ID read from the device (available for request detection).
/// </summary>
public string PcbId { get; set; }
/// <summary>
/// Error message describing why detection failed (if not successful).
/// </summary>
public string ErrorMessage { get; set; }
}
/// </summary>
/// <param name="slot">Slot number.</param>
/// <returns>
/// Result containing success status and detected port name.
/// </returns>
/// <example>
/// <code>
/// var api = new Api2();
/// var result = api.DetectStreamingPort(3);
///
/// if (result.Success)
/// {
/// Console.WriteLine($"Port: {result.PortName}");
/// }
/// else
/// {
/// Console.WriteLine("Streaming detection failed");
/// }
/// </code>
/// </example>
public PortDetectionResult DetectStreamingPort(int slot)
{
if (slot <= 0)
throw new ArgumentOutOfRangeException(nameof(slot));
using (var mb = new MeterBatch())
using (var meter = new GenesisMeter())
{
//meter.SetupFromConfigFile(slot, false);
mb.AddMeter(meter);
var rawData = new ConcurrentBag<string>();
meter.StreamingPort.OnRawRecordReceived += (o, rawMsg) =>
{
var data = (string)rawMsg.GetData();
rawData.Add(data);
};
Thread.Sleep(500);
var success = rawData.Any();
var portName = meter.StreamingPort.GetPortName();
return new PortDetectionResult
{
Success = success,
Slot = slot,
PortName = portName,
ErrorMessage = success ? null : "No streaming data received."
};
}
}
/// <summary>
/// Detects the request port by attempting to read the PCB ID.
/// </summary>
/// <param name="slot">Slot number.</param>
/// <returns>
/// Result containing success status, port name, and PCB ID if successful.
/// </returns>
/// <example>
/// <code>
/// var api = new Api2();
/// var result = api.DetectRequestPort(3);
///
/// if (result.Success)
/// {
/// Console.WriteLine($"PCB ID: {result.PcbId}");
/// }
/// else
/// {
/// Console.WriteLine("Detection failed");
/// }
/// </code>
/// </example>
public PortDetectionResult DetectRequestPort(int slot)
{
if (slot <= 0)
throw new ArgumentOutOfRangeException(nameof(slot));
using (var mb = new MeterBatch())
using (var meter = new GenesisMeter())
{
//meter.SetupFromConfigFile(slot, false);
mb.AddMeter(meter);
meter.Logout();
var pcbId = meter.GetPcbId();
var success = !string.IsNullOrEmpty(pcbId);
var portName = meter.RequestPort.GetPortName();
return new PortDetectionResult
{
Success = success,
Slot = slot,
PortName = portName,
PcbId = pcbId,
ErrorMessage = success ? null : "PCB ID was empty."
};
}
}
#endregion
#region API - PCB ID region
/// <summary>
/// Reads PCB ID for the specified slot.
/// </summary>
/// <param name="slot">Slot number.</param>
/// <returns>PCB ID read from the meter.</returns>
/// <example>
/// <code>
/// var api = new Api2();
/// string pcbId = api.GetPcbId(3);
/// Console.WriteLine(pcbId);
/// </code>
/// </example>
public string GetPcbId(int slot)
{
if (slot <= 0)
throw new ArgumentOutOfRangeException(nameof(slot), "Slot number must be greater than zero.");
using (var mb = new MeterBatch())
using (var meter = new GenesisMeter())
{
meter.SetupFromConfigFile(slot, false);
mb.AddMeter(meter);
meter.Logout();
return meter.GetPcbId();
}
}
#endregion
#region Password and Login
/// <summary>
/// Sets meter password.
/// </summary>
public bool SetMeterPassword(string password)
{
EnsureConnected();
if (string.IsNullOrWhiteSpace(password))
throw new ArgumentException("Password cannot be null or empty.", nameof(password));
try
{
// Replace this with the real Genesis API call if available.
// Example:
// return _currentGenesis.SetMeterPassword(password);
var result = WriteRegister("SECURITY_Password", password, true, true);
return result.Success;
}
catch (Exception ex)
{
Logger.Value.Error(ex, "SetMeterPassword failed.");
return false;
}
}
/// <summary>
/// Performs login using provided password.
/// </summary>
public bool Login(string password)
{
if (_currentGenesis == null)
throw new InvalidOperationException("Genesis meter is not initialized. Call Connect first.");
if (string.IsNullOrWhiteSpace(password))
throw new ArgumentException("Password cannot be null or empty.", nameof(password));
try
{
// IMPORTANT:
// Replace with actual Genesis API method if available
// Variant A direct login method (preferred)
// return _currentGenesis.Login(password);
// Variant B if password must be set first
// _currentGenesis.Password = password;
// return _currentGenesis.Login();
// TEMP fallback (if no direct method known)
bool result = _currentGenesis.Login();
if (!result)
Logger.Value.Warn("Login failed.");
return result;
}
catch (Exception ex)
{
Logger.Value.Error(ex, "Login failed.");
return false;
}
}
#endregion
#region API - Connect
public class InitResult
{
public bool Success { get; set; }
public int Slot { get; set; }
public string ErrorMessage { get; set; }
public string InterfaceVersion { get; set; }
public bool InterfaceSupportsFwVersion { get; set; }
}
/// <summary>
/// Represents the result of a connect operation.
/// </summary>
public class ConnectResult
{
/// <summary>
/// Indicates whether the connect operation was successful.
/// </summary>
public bool Success { get; set; }
/// <summary>
/// Slot number used for connect.
/// </summary>
public int Slot { get; set; }
/// <summary>
/// Connected PCB ID.
/// </summary>
public string PcbId { get; set; }
/// <summary>
/// Indicates whether the meter is logged on.
/// </summary>
public bool IsLoggedOn { get; set; }
/// <summary>
/// Firmware version reported by the meter.
/// </summary>
public string FwVersion { get; set; }
/// <summary>
/// Interface version from configuration.
/// </summary>
public string InterfaceVersion { get; set; }
/// <summary>
/// Indicates whether the loaded configuration supports the detected firmware version.
/// </summary>
public bool InterfaceSupportsFwVersion { get; set; }
/// <summary>
/// Registers available after successful connect.
/// </summary>
public List<RegisterSnapshot> Registers { get; set; } = new List<RegisterSnapshot>();
/// <summary>
/// Error message if connect failed.
/// </summary>
public string ErrorMessage { get; set; }
}
/// <summary>
/// Represents one register returned after connect.
/// </summary>
public class RegisterSnapshot
{
public string Name { get; set; }
public string Type { get; set; }
public string RawValue { get; set; }
public string Min { get; set; }
public string Max { get; set; }
public string Description { get; set; }
public string Version { get; set; }
public string IsAvailable { get; set; }
public string Privilege { get; set; }
}
public InitResult InitOneMeterFromExtern(Int32 slotNo, ConfigSource useConfigSource, PasswordSource usePasswordSource, PortConfig? requestPort, PortConfig? streamingPort)
{
try
{
if (slotNo <= 0)
throw new ArgumentOutOfRangeException(nameof(slotNo), "Slot number must be greater than zero.");
//_meterBatch.RemoveMeter(slotNo);
_currentGenesis?.DisposeMeter();
_currentGenesis = new GenesisMeter();
_currentGenesis.UseOfflinePasswords = usePasswordSource == PasswordSource.OfflineFile;
_currentGenesis.usePasswordSource = usePasswordSource;
_currentGenesis.useConfigSource = useConfigSource;
_currentGenesis.SetupFromExternConfig(
slotNo,
requestPort,
streamingPort,
true);
_meterBatch.AddMeter(_currentGenesis);
return new InitResult
{
Success = true,
Slot = slotNo,
InterfaceVersion = _currentGenesis.InterfaceInfo?.InterfaceVersion,
InterfaceSupportsFwVersion = _currentGenesis.InterfaceSupportsFwVersion
};
}
catch (Exception ex)
{
//_meterBatch.RemoveAllMeters();
_currentGenesis?.DisposeMeter();
_currentGenesis = null;
return new InitResult
{
Success = false,
Slot = slotNo,
ErrorMessage = ex.Message
};
}
}
/// <summary>
/// Connects to a Genesis meter for the specified slot.
/// </summary>
/// <param name="slotNo">Slot number.</param>
/// <param name="useOfflinePasswords">Specifies whether offline passwords should be used.</param>
/// <returns>
/// Connect operation result including PCB ID, firmware/configuration info, and register snapshots.
/// </returns>
/// <example>
/// <code>
/// var api = new GenesisAPI();
/// var result = api.Connect(3, true);
///
/// if (result.Success)
/// {
/// Console.WriteLine(result.PcbId);
/// Console.WriteLine(result.InterfaceVersion);
/// }
/// else
/// {
/// Console.WriteLine(result.ErrorMessage);
/// }
/// </code>
/// </example>
public ConnectResult ConnectOneMeter(int slotNo)
{
try
{
// Validate input
if (slotNo <= 0)
throw new ArgumentOutOfRangeException(nameof(slotNo), "Slot number must be greater than zero.");
// Find meter in batch by slot
var meter = _meterBatch.ListOfMeters
.OfType<GenesisMeter>()
.FirstOrDefault(m => m.Slot == slotNo);
// Meter not initialized
if (meter == null)
{
return new ConnectResult
{
Success = false,
Slot = slotNo,
ErrorMessage = $"Meter for slot {slotNo} not found in batch."
};
}
// Set current working meter
_currentGenesis = meter;
// Perform login for meters in batch
_meterBatch.MetersLogin();
// Validate connection result
if (!_currentGenesis.IsLoggedOn && string.IsNullOrEmpty(_currentGenesis.PcbId))
{
return new ConnectResult
{
Success = false,
Slot = slotNo,
IsLoggedOn = false,
PcbId = _currentGenesis.PcbId,
ErrorMessage = "Cannot read out PcbId. Access to Cordonel denied."
};
}
// Build successful result
var result = new ConnectResult
{
Success = _currentGenesis.IsLoggedOn,
Slot = slotNo,
PcbId = _currentGenesis.PcbId,
IsLoggedOn = _currentGenesis.IsLoggedOn,
FwVersion = _currentGenesis.FwVersion,
InterfaceVersion = _currentGenesis.InterfaceInfo?.InterfaceVersion,
InterfaceSupportsFwVersion = _currentGenesis.InterfaceSupportsFwVersion
};
return result;
}
catch (Exception ex)
{
// Return failure result on exception
return new ConnectResult
{
Success = false,
Slot = slotNo,
ErrorMessage = ex.Message
};
}
}
/// <summary>
/// Connects to a Genesis meter for the specified slot.
/// </summary>
/// <param name="slotNo">Slot number.</param>
/// <param name="useOfflinePasswords">Specifies whether offline passwords should be used.</param>
/// <returns>
/// Connect operation result including PCB ID, firmware/configuration info, and register snapshots.
/// </returns>
/// <example>
/// <code>
/// var api = new GenesisAPI();
/// var result = api.Connect(3, true);
///
/// if (result.Success)
/// {
/// Console.WriteLine(result.PcbId);
/// Console.WriteLine(result.InterfaceVersion);
/// }
/// else
/// {
/// Console.WriteLine(result.ErrorMessage);
/// }
/// </code>
/// </example>
public ConnectResult ConnectAllMeters(int slotNo)
{
/*try
{
if (slotNo <= 0)
throw new ArgumentOutOfRangeException(nameof(slotNo), "Slot number must be greater than zero.");
_currentGenesis?.DisposeMeter();
_meterBatch.RemoveAllMeters();
_currentGenesis = null;
_currentGenesis = new GenesisMeter();
_currentGenesis.UseOfflinePasswords = usePasswordSource == PasswordSource.OfflineFile;
_currentGenesis.usePasswordSource = usePasswordSource;
_currentGenesis.useConfigSource = useConfigSource;
_currentGenesis.SetupFromConfigFile(slotNo);//...MF
_currentGenesis.SetupFromExternConfig(slotNo);
_meterBatch.AddMeter(_currentGenesis);
_meterBatch.MetersLogin();
if (!_currentGenesis.IsLoggedOn && string.IsNullOrEmpty(_currentGenesis.PcbId))
{
return new ConnectResult
{
Success = false,
Slot = slotNo,
IsLoggedOn = false,
PcbId = _currentGenesis.PcbId,
ErrorMessage = "Cannot read out PcbId. Access to Cordonel denied."
};
}
var result = new ConnectResult
{
Success = _currentGenesis.IsLoggedOn,
Slot = slotNo,
PcbId = _currentGenesis.PcbId,
IsLoggedOn = _currentGenesis.IsLoggedOn,
FwVersion = _currentGenesis.FwVersion,
InterfaceVersion = _currentGenesis.InterfaceInfo?.InterfaceVersion,
InterfaceSupportsFwVersion = _currentGenesis.InterfaceSupportsFwVersion
};
foreach (var item in _currentGenesis.GetRegistersDic())
{
var from = item.Key.RegisterDetail.Version.First.HasValue
? item.Key.RegisterDetail.Version.First.Value.ToString()
: "-";
var to = item.Key.RegisterDetail.Version.Last.HasValue
? item.Key.RegisterDetail.Version.Last.Value.ToString()
: "-";
result.Registers.Add(new RegisterSnapshot
{
Name = item.Key.GetIdent(),
Type = item.Key.DataType.Name,
RawValue = BitConverter.ToString(item.Value).Replace("-", " "),
Min = item.Key.Minimum?.ToString(),
Max = item.Key.Maximum?.ToString(),
Description = item.Key.RegisterDetail.Description,
Version = $"from {from} to {to}",
IsAvailable = item.Key.IsAvailable.ToString(),
Privilege = item.Key.RegisterDetail.Privilege.Lvl8.ToString()
});
}
return result;
}
catch (Exception ex)
{
_meterBatch.RemoveAllMeters();
_currentGenesis?.DisposeMeter();
return new ConnectResult
{
Success = false,
Slot = slotNo,
ErrorMessage = ex.Message
};
}*/
return null;
}
#endregion
#region Meter Registers
/// <summary>
/// Result of a register read operation.
/// </summary>
public class RegisterReadResult
{
/// <summary>
/// Indicates whether the read operation was successful.
/// </summary>
public bool Success { get; set; }
/// <summary>
/// Name of the register.
/// </summary>
public string RegisterName { get; set; }
/// <summary>
/// Raw bytes returned from the device.
/// </summary>
public byte[] RawBytes { get; set; }
/// <summary>
/// Raw value formatted as hexadecimal string.
/// </summary>
public string RawHex { get; set; }
/// <summary>
/// Converted value based on register data type (if possible).
/// </summary>
public object TypedValue { get; set; }
/// <summary>
/// String representation of the converted value.
/// </summary>
public string TypedValueText { get; set; }
/// <summary>
/// Data type of the register.
/// </summary>
public string DataType { get; set; }
/// <summary>
/// Error message if operation failed.
/// </summary>
public string ErrorMessage { get; set; }
}
/// <summary>
/// Result of a register write operation.
/// </summary>
public class RegisterWriteResult
{
/// <summary>
/// Indicates whether the write operation was successful.
/// </summary>
public bool Success { get; set; }
/// <summary>
/// Name of the register.
/// </summary>
public string RegisterName { get; set; }
/// <summary>
/// Value that was written to the register.
/// </summary>
public object WrittenValue { get; set; }
/// <summary>
/// Indicates whether configuration was stored to the device.
/// </summary>
public bool StoreToDevice { get; set; }
/// <summary>
/// Indicates whether system state refresh was triggered.
/// </summary>
public bool RefreshSystemState { get; set; }
/// <summary>
/// Error message if operation failed.
/// </summary>
public string ErrorMessage { get; set; }
}
//Helper methods
/// <summary>
/// Ensures that the meter is connected and logged on.
/// </summary>
private void EnsureConnected()
{
if (_currentGenesis == null)
throw new InvalidOperationException("Genesis meter is not initialized. Call Connect first.");
if (!_currentGenesis.IsLoggedOn)
throw new InvalidOperationException("Genesis meter is not logged on. Call Connect first.");
}
/// <summary>
/// Finds register definition by name.
/// </summary>
private RegisterDefinition FindRegisterDefinition(string registerName)
{
if (string.IsNullOrWhiteSpace(registerName))
throw new ArgumentException("Register name cannot be null or empty.", nameof(registerName));
var match = _currentGenesis
.GetRegistersDic()
.Keys
.FirstOrDefault(r => string.Equals(r.GetIdent(), registerName, StringComparison.OrdinalIgnoreCase));
if (match == null)
throw new KeyNotFoundException($"Register '{registerName}' was not found.");
return match;
}
/// <summary>
/// Converts byte array to hex string.
/// </summary>
private string ToHex(byte[] data)
{
if (data == null || data.Length == 0)
return string.Empty;
return BitConverter.ToString(data).Replace("-", " ");
}
//Read register
/// <summary>
/// Reads register value by register name.
/// </summary>
public RegisterReadResult ReadRegister(string registerName)
{
try
{
EnsureConnected();
var register = FindRegisterDefinition(registerName);
var raw = _currentGenesis.ReadRegister(registerName);
object typedValue = null;
string typedValueText = null;
try
{
typedValue = ConvertRegisterValue(register, raw);
typedValueText = typedValue?.ToString();
}
catch
{
// Ignore conversion errors, raw value is still valid
}
return new RegisterReadResult
{
Success = true,
RegisterName = registerName,
RawBytes = raw,
RawHex = ToHex(raw),
TypedValue = typedValue,
TypedValueText = typedValueText,
DataType = register.DataType?.Name
};
}
catch (Exception ex)
{
Logger.Value.Error(ex, $"ReadRegister failed for '{registerName}'.");
return new RegisterReadResult
{
Success = false,
RegisterName = registerName,
ErrorMessage = ex.Message
};
}
}
//Typed conversion
/// <summary>
/// Converts raw register value to a typed value based on register definition.
/// </summary>
private object ConvertRegisterValue(RegisterDefinition register, byte[] raw)
{
var typeName = register.DataType?.Name;
switch (typeName)
{
case "Boolean":
return RegisterConverter.ByteArrayToValue<bool>(raw);
case "Byte":
return RegisterConverter.ByteArrayToValue<byte>(raw);
case "Int32":
return RegisterConverter.ByteArrayToValue<int>(raw);
case "UInt32":
return RegisterConverter.ByteArrayToValue<uint>(raw);
case "Double":
return RegisterConverter.ByteArrayToValue<double>(raw);
case "Single":
return RegisterConverter.ByteArrayToValue<float>(raw);
case "String":
return Encoding.ASCII.GetString(raw).TrimEnd('\0');
default:
return ToHex(raw);
}
}
//Generic login
/// <summary>
/// Reads register and converts it directly to specified type.
/// </summary>
public T ReadRegisterValue<T>(string registerName)
{
EnsureConnected();
var raw = _currentGenesis.ReadRegister(registerName);
return RegisterConverter.ByteArrayToValue<T>(raw);
}
//Write register
/// <summary>
/// Writes value to register.
/// </summary>
public RegisterWriteResult WriteRegister(
string registerName,
object value,
bool storeToDevice = false,
bool refreshSystemState = false)
{
try
{
EnsureConnected();
bool writeOk = _currentGenesis.WriteRegister(registerName, value);
if (!writeOk)
{
return new RegisterWriteResult
{
Success = false,
RegisterName = registerName,
WrittenValue = value,
ErrorMessage = "Write operation failed."
};
}
if (storeToDevice)
{
if (!_currentGenesis.StoreAllConfigurations())
{
return new RegisterWriteResult
{
Success = false,
RegisterName = registerName,
WrittenValue = value,
ErrorMessage = "StoreAllConfigurations failed."
};
}
}
if (refreshSystemState)
{
if (!_currentGenesis.WriteRegister("SENSUSRADIO_SYSTEMSTATE", 0xFF, true, false))
{
return new RegisterWriteResult
{
Success = false,
RegisterName = registerName,
WrittenValue = value,
ErrorMessage = "System state refresh failed."
};
}
}
return new RegisterWriteResult
{
Success = true,
RegisterName = registerName,
WrittenValue = value,
StoreToDevice = storeToDevice,
RefreshSystemState = refreshSystemState
};
}
catch (Exception ex)
{
Logger.Value.Error(ex, $"WriteRegister failed for '{registerName}'.");
return new RegisterWriteResult
{
Success = false,
RegisterName = registerName,
WrittenValue = value,
ErrorMessage = ex.Message
};
}
}
//Bulk operations
/// <summary>
/// Reads multiple registers.
/// </summary>
public List<RegisterReadResult> ReadRegisters(IEnumerable<string> registerNames)
{
var result = new List<RegisterReadResult>();
foreach (var name in registerNames)
{
result.Add(ReadRegister(name));
}
return result;
}
/// <summary>
/// Writes multiple registers.
/// </summary>
public List<RegisterWriteResult> WriteRegisters(
Dictionary<string, object> registerValues,
bool storeToDevice = false,
bool refreshSystemState = false)
{
var results = new List<RegisterWriteResult>();
int index = 0;
int total = registerValues.Count;
foreach (var pair in registerValues)
{
bool doStore = storeToDevice && index == total - 1;
bool doRefresh = refreshSystemState && index == total - 1;
results.Add(WriteRegister(pair.Key, pair.Value, doStore, doRefresh));
index++;
}
return results;
}
//Disconnect
/// <summary>
/// Disconnects from the meter and releases resources.
/// </summary>
public void Disconnect()
{
try
{
if (_currentGenesis != null && _currentGenesis.IsLoggedOn)
{
_currentGenesis.Logout();
}
}
catch (Exception ex)
{
Logger.Value.Error(ex, "Disconnect failed.");
}
finally
{
_meterBatch.RemoveAllMeters();
_currentGenesis?.DisposeMeter();
_currentGenesis = null;
_currentPcbId = string.Empty;
}
}
#endregion
}
}