722 lines
25 KiB
C#
722 lines
25 KiB
C#
using GenesisCordonelInterface.API;
|
|
using log4net;
|
|
///
|
|
/// Copyright (c) 2015-2021 Sensus Slovensko a.s.
|
|
///
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
using System.Windows.Forms;
|
|
using TBF.Rig.BridgeComponents.GciBridge.Interfaces;
|
|
using TBF.Rig.BridgeComponents.GciBridge.UI;
|
|
using TBF.Rig.Generic;
|
|
using TBF.Rig.Input.DataStorage.UniDataStorageReader;
|
|
using TBF.Rig.Input.DataStorage.UniDataStorageReader.Searching.Database;
|
|
using static TBF.Rig.BridgeComponents.GciBridge.Interfaces.PublicModels;
|
|
using GciGUIType = GenesisCordonelInterface.UI.MainView;
|
|
using GciPublicModels = GenesisCordonelInterface.API.PublicModels;
|
|
using GciType = GenesisCordonelInterface.API.InterfaceOutsideToGCI;
|
|
using UdsReaderType = TBF.Rig.Input.DataStorage.UniDataStorageReader.Reader;
|
|
using UDSRPublicModels = TBF.Rig.Input.DataStorage.UniDataStorageReader.Interfaces.PublicModels;
|
|
using UdsWriterType = TBF.Rig.Output.DataStorage.UniDataStorageWriter.Writer;
|
|
|
|
namespace TBF.Rig.BridgeComponents.GciBridge
|
|
{
|
|
/// <summary>
|
|
/// TBF bridge component for integration with the sibling GCI project.
|
|
/// The component can be linked to UniDataStorage reader and writer components.
|
|
/// </summary>
|
|
public class GciBridge : ComponentBase
|
|
{
|
|
private static readonly ILog log = LogManager.GetLogger(typeof(GciBridge));
|
|
|
|
public override string ToString()
|
|
{
|
|
return string.Format("{0}({1})", ClassName, Cfg.ToString(-1));
|
|
}
|
|
|
|
readonly GciBridgeCfg gciBridgeCfg;
|
|
|
|
readonly UdsReaderType reader;
|
|
readonly UdsWriterType writer;
|
|
|
|
//diag GUI for GCI
|
|
GciGUIType gciGUI;
|
|
Form gciGuiHostForm;
|
|
|
|
//diag GUI for GciBridge
|
|
public UserControl gciBridgeGUI;
|
|
public 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 GciBridgeCfg GciBridgeCfg { get { return gciBridgeCfg; } }
|
|
|
|
public UdsReaderType GetReader()
|
|
{
|
|
return reader;
|
|
}
|
|
|
|
public UdsWriterType GetWriter()
|
|
{
|
|
return writer;
|
|
}
|
|
|
|
public GciBridge() { }
|
|
|
|
public GciBridge(IComponentCfg cfg, IList<IComponent> components)
|
|
: base(cfg)
|
|
{
|
|
gciBridgeCfg = cfg as GciBridgeCfg;
|
|
if (gciBridgeCfg == null) throw new Exception("Invalid GciBridgeCfg.");
|
|
|
|
if (!string.IsNullOrEmpty(gciBridgeCfg.ReaderName))
|
|
{
|
|
reader = TbfComponents.FindComponent(gciBridgeCfg.ReaderName, components) as UdsReaderType;
|
|
if (reader == null) throw new Exception("Cannot find reader component '" + gciBridgeCfg.ReaderName + "'");
|
|
}
|
|
|
|
if (!string.IsNullOrEmpty(gciBridgeCfg.WriterName))
|
|
{
|
|
writer = TbfComponents.FindComponent(gciBridgeCfg.WriterName, components) as UdsWriterType;
|
|
if (writer == null) throw new Exception("Cannot find writer component '" + gciBridgeCfg.WriterName + "'");
|
|
}
|
|
|
|
Initialize();
|
|
}
|
|
|
|
public override void Initialize()
|
|
{
|
|
if (gciBridgeCfg.EnableExternalAccess)
|
|
{
|
|
TryInitializeExternalInterface();
|
|
}
|
|
|
|
if (gciBridgeCfg.EnableGuiAccess)
|
|
{
|
|
TryInitializeGciGui();
|
|
|
|
if (gciBridgeCfg.ShowGuiOnInitialize)
|
|
{
|
|
ShowGciGui();
|
|
}
|
|
}
|
|
|
|
log.FatalFormat("{0} initialized: {1}", Name, this);
|
|
}
|
|
|
|
void TryInitializeGciBridgeGui()
|
|
{
|
|
try
|
|
{
|
|
if (gciBridgeGuiForm != null && !gciBridgeGuiForm.IsDisposed)
|
|
return;
|
|
|
|
gciBridgeGuiForm = new MainForm(this);
|
|
gciBridgeGuiForm.Text = "Gci Bridge GUI";
|
|
gciBridgeGuiForm.Width = 1300;
|
|
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)
|
|
{
|
|
log.Error("Failed to initialize GciBridge GUI view.", ex);
|
|
}
|
|
}
|
|
|
|
void TryInitializeGciGui()
|
|
{
|
|
try
|
|
{
|
|
if (gciGuiHostForm != null && !gciGuiHostForm.IsDisposed)
|
|
return;
|
|
|
|
gciGUI = new GciGUIType();
|
|
gciGUI.Dock = DockStyle.Fill;
|
|
|
|
gciGuiHostForm = new Form();
|
|
gciGuiHostForm.Text = "Genesis Cordonel Interface";
|
|
gciGuiHostForm.Width = 1300;
|
|
gciGuiHostForm.Height = 600;
|
|
gciGuiHostForm.StartPosition = FormStartPosition.CenterScreen;
|
|
|
|
gciGuiHostForm.Controls.Add(gciGUI);
|
|
|
|
log.InfoFormat("{0}: GCI GUI view initialized.", Name);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
log.Error("Failed to initialize GCI GUI view.", ex);
|
|
}
|
|
}
|
|
|
|
void TryInitializeExternalInterface()
|
|
{
|
|
try
|
|
{
|
|
if (gciExternalInterface != null)
|
|
return;
|
|
|
|
gciExternalInterface = new GciType();
|
|
|
|
log.InfoFormat("{0}: GCI external interface initialized.", Name);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
log.Error("Failed to initialize GCI external interface.", ex);
|
|
}
|
|
}
|
|
|
|
public void ShowGciGui()
|
|
{
|
|
if (!gciBridgeCfg.EnableGuiAccess) return;
|
|
|
|
if (gciGuiHostForm == null || gciGuiHostForm.IsDisposed)
|
|
{
|
|
TryInitializeGciGui();
|
|
}
|
|
|
|
if (gciGuiHostForm == null) return;
|
|
|
|
gciGuiHostForm.Show();
|
|
gciGuiHostForm.BringToFront();
|
|
|
|
log.InfoFormat("{0}: ShowGciGui invoked.", Name);
|
|
}
|
|
|
|
public void HideGciGui()
|
|
{
|
|
if (!gciBridgeCfg.EnableGuiAccess) return;
|
|
if (gciGuiHostForm == null || gciGuiHostForm.IsDisposed) return;
|
|
|
|
gciGuiHostForm.Hide();
|
|
|
|
log.InfoFormat("{0}: HideGciGui invoked.", Name);
|
|
}
|
|
|
|
public void ShowGui()
|
|
{
|
|
if (!gciBridgeCfg.EnableGuiAccess) return;
|
|
|
|
if (gciBridgeGuiForm == null || gciBridgeGuiForm.IsDisposed)
|
|
{
|
|
TryInitializeGciBridgeGui();
|
|
}
|
|
|
|
if (gciBridgeGuiForm == null || gciBridgeGuiForm.IsDisposed)
|
|
return;
|
|
|
|
gciBridgeGuiForm.Show();
|
|
gciBridgeGuiForm.BringToFront();
|
|
|
|
log.InfoFormat("{0}: ShowGui invoked.", Name);
|
|
}
|
|
|
|
public void HideGui()
|
|
{
|
|
if (!gciBridgeCfg.EnableGuiAccess) return;
|
|
if (gciBridgeGuiForm == null || gciBridgeGuiForm.IsDisposed) return;
|
|
|
|
gciBridgeGuiForm.Hide();
|
|
|
|
log.InfoFormat("{0}: HideGciGui invoked.", Name);
|
|
}
|
|
|
|
void EnsureExternalInterface()
|
|
{
|
|
if (!gciBridgeCfg.EnableExternalAccess)
|
|
throw new Exception("GCI external access is disabled.");
|
|
|
|
if (!IsExternalInitialized)
|
|
TryInitializeExternalInterface();
|
|
|
|
if (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.");
|
|
}
|
|
|
|
// API:
|
|
#region ======================================= GCI Public Interface =======================================
|
|
|
|
/*/// <summary>
|
|
/// Initializes one GCI slot through the external GCI interface.
|
|
///
|
|
/// Trace:
|
|
/// GciBridge.InitSlotAsync()
|
|
/// -> InterfaceOutsideToGCI.InitSlotAsync()
|
|
/// -> InterfaceGCIToLaatzen.InitOneMeterFromExternAsync()
|
|
/// -> per-slot GCI worker
|
|
/// -> GenesisMeter.SetupFromExternConfig()
|
|
/// </summary>
|
|
/// <param name="request">Public GCI slot initialization request.</param>
|
|
/// <returns>Initialization result for the requested slot.</returns>
|
|
public async Task<GciPublicModels.GciInitSlotResult> InitSlotAsync(GciPublicModels.GciInitSlotRequest request)
|
|
{
|
|
EnsureExternalInterface();
|
|
|
|
if (request == null)
|
|
throw new ArgumentNullException("request");
|
|
|
|
if (request.SlotId <= 0)
|
|
throw new ArgumentException("Invalid slot id.");
|
|
|
|
GciPublicModels.GciInitSlotResult result =
|
|
await gciExternalInterface.InitSlotAsync(request);
|
|
|
|
log.InfoFormat("{0}: InitSlotAsync invoked. {1}, Result={2}", Name, request, result);
|
|
|
|
return result;
|
|
}*/
|
|
|
|
/// <summary>
|
|
/// Initializes one GCI slot through the external GCI interface.
|
|
///
|
|
/// Trace:
|
|
/// GciBridge.InitSlotAsync()
|
|
/// -> InterfaceOutsideToGCI.InitSlotAsync()
|
|
/// -> InterfaceGCIToLaatzen.InitSlotAsync()
|
|
/// -> per-slot GCI worker
|
|
/// -> GenesisMeter.SetupFromExternConfig()
|
|
/// </summary>
|
|
/// <param name="request">Public GCI slot initialization request.</param>
|
|
/// <returns>Initialization result for the requested slot.</returns>
|
|
public async Task<GciPublicModels.GciInitSlotResult> InitSlotAsync(
|
|
GciPublicModels.GciInitSlotRequest request)
|
|
{
|
|
|
|
if (request == null)
|
|
throw new ArgumentNullException(nameof(request));
|
|
|
|
if (request.SlotId <= 0)
|
|
throw new ArgumentException("Invalid slot id.");
|
|
|
|
if (string.Equals(request.RequestPort?.Type, "SIMULATE", StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
log.InfoFormat("{0}: InitSlotAsync invoked. {1}, SIMULATE", Name, request);
|
|
await Task.Delay(500);
|
|
log.InfoFormat("{0}: InitSlotAsync SIMULATE finished.", Name);
|
|
|
|
return new GciPublicModels.GciInitSlotResult()
|
|
{
|
|
SlotId = request.SlotId,
|
|
Success = true,
|
|
AlreadyExists = false,
|
|
Updated = false,
|
|
Message = "Simulated",
|
|
};
|
|
}
|
|
|
|
EnsureExternalInterface();
|
|
|
|
var result = await gciExternalInterface.InitSlotAsync(request);
|
|
|
|
log.InfoFormat("{0}: InitSlotAsync invoked. {1}, Result={2}", Name, request, result);
|
|
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Updates an already initialized GCI slot.
|
|
///
|
|
/// Trace:
|
|
/// GciBridge.UpdateSlotAsync()
|
|
/// -> InterfaceOutsideToGCI.UpdateSlotAsync()
|
|
/// -> InterfaceGCIToLaatzen.UpdateSlotAsync()
|
|
/// -> per-slot GCI worker
|
|
/// -> GenesisMeter.SetupFromExternConfig()
|
|
/// </summary>
|
|
/// <param name="request">Public GCI slot update request.</param>
|
|
/// <returns>Update result for the requested slot.</returns>
|
|
public async Task<GciPublicModels.GciInitSlotResult> UpdateSlotAsync(
|
|
GciPublicModels.GciInitSlotRequest request)
|
|
{
|
|
|
|
if (request == null)
|
|
throw new ArgumentNullException(nameof(request));
|
|
|
|
if (request.SlotId <= 0)
|
|
throw new ArgumentException("Invalid slot id.");
|
|
|
|
if (string.Equals(request.RequestPort?.Type, "SIMULATE", StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
log.InfoFormat("{0}: UpdateSlotAsync invoked. {1}, SIMULATE", Name, request);
|
|
await Task.Delay(500);
|
|
log.InfoFormat("{0}: UpdateSlotAsync SIMULATE finished.", Name);
|
|
|
|
return new GciPublicModels.GciInitSlotResult()
|
|
{
|
|
SlotId = request.SlotId,
|
|
Success = true,
|
|
AlreadyExists = false,
|
|
Updated = true,
|
|
Message = "Simulated",
|
|
};
|
|
}
|
|
|
|
EnsureExternalInterface();
|
|
|
|
var result = await gciExternalInterface.UpdateSlotAsync(request);
|
|
|
|
log.InfoFormat("{0}: UpdateSlotAsync invoked. {1}, Result={2}", Name, request, result);
|
|
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Reads current information about one initialized GCI slot.
|
|
///
|
|
/// Trace:
|
|
/// GciBridge.GetSlotAsync()
|
|
/// -> InterfaceOutsideToGCI.GetSlotAsync()
|
|
/// -> InterfaceGCIToLaatzen.GetOneMeterInfo()
|
|
/// -> per-slot GCI worker
|
|
/// -> MeterBatch / GenesisMeter snapshot
|
|
/// </summary>
|
|
/// <param name="slotId">Slot number.</param>
|
|
/// <returns>Current public slot information.</returns>
|
|
public async Task<GciPublicModels.GciSlotInfo> GetSlotAsync(int slotId)
|
|
{
|
|
EnsureExternalInterface();
|
|
|
|
if (slotId <= 0)
|
|
throw new ArgumentException("Invalid slot id.");
|
|
|
|
GciPublicModels.GciSlotInfo result =
|
|
await gciExternalInterface.GetSlotAsync(slotId);
|
|
|
|
log.InfoFormat("{0}: GetSlotAsync({1}) invoked. Result={2}", Name, slotId, result);
|
|
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Clears all initialized GCI slots and related GCI worker state.
|
|
///
|
|
/// Trace:
|
|
/// GciBridge.CleanSlotsAsync()
|
|
/// -> InterfaceOutsideToGCI.CleanSlotsAsync()
|
|
/// -> InterfaceGCIToLaatzen.CleanSlotsAsync()
|
|
/// -> MeterBatch cleanup
|
|
/// -> selected slot cleanup
|
|
/// -> worker cleanup
|
|
/// </summary>
|
|
/// <returns>Cleanup operation result.</returns>
|
|
public async Task<GciPublicModels.GciCleanSlotsResult> CleanSlotsAsync()
|
|
{
|
|
EnsureExternalInterface();
|
|
|
|
GciPublicModels.GciCleanSlotsResult result =
|
|
await gciExternalInterface.CleanSlotsAsync();
|
|
|
|
log.InfoFormat("{0}: CleanSlotsAsync invoked.", Name);
|
|
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Reads PCB ID from the meter assigned to the requested slot.
|
|
///
|
|
/// Trace:
|
|
/// GciBridge.GetPcbIdAsync()
|
|
/// -> InterfaceOutsideToGCI.GetPcbIdAsync()
|
|
/// -> InterfaceGCIToLaatzen.GetPcbIdAsync()
|
|
/// -> per-slot GCI worker
|
|
/// -> GenesisMeter.GetPcbId()
|
|
/// </summary>
|
|
/// <param name="slotId">Slot number.</param>
|
|
/// <param name="token">Cancellation token.</param>
|
|
/// <returns>PCB ID read result.</returns>
|
|
public async Task<GciPublicModels.GciGetPcbIdResult> GetPcbIdAsync(
|
|
int slotId,
|
|
CancellationToken token = default)
|
|
{
|
|
EnsureExternalInterface();
|
|
|
|
if (slotId <= 0)
|
|
throw new ArgumentException("Invalid slot id.");
|
|
|
|
var result = await gciExternalInterface.GetPcbIdAsync(slotId, token);
|
|
|
|
log.InfoFormat("{0}: GetPcbIdAsync({1}) invoked. Result={2}", Name, slotId, result);
|
|
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Connects/logs in to the meter assigned to the requested slot.
|
|
///
|
|
/// Trace:
|
|
/// GciBridge.ConnectAsync()
|
|
/// -> InterfaceOutsideToGCI.ConnectOneSlotAsync()
|
|
/// -> InterfaceGCIToLaatzen.ConnectOneMeterAsync()
|
|
/// -> per-slot GCI worker
|
|
/// -> MeterBatch.MetersLogin()
|
|
/// -> GenesisMeter register snapshot
|
|
/// </summary>
|
|
/// <param name="slotId">Slot number.</param>
|
|
/// <param name="token">Cancellation token.</param>
|
|
/// <returns>Connection result including firmware/interface information.</returns>
|
|
public async Task<GciPublicModels.GciConnectResult> ConnectAsync(
|
|
int slotId,
|
|
CancellationToken token = default)
|
|
{
|
|
EnsureExternalInterface();
|
|
|
|
if (slotId <= 0)
|
|
throw new ArgumentException("Invalid slot id.");
|
|
|
|
var result = await gciExternalInterface.ConnectOneSlotAsync(slotId, token);
|
|
|
|
log.InfoFormat("{0}: ConnectAsync({1}) invoked. Result={2}", Name, slotId, result);
|
|
|
|
return result;
|
|
}
|
|
|
|
public Task<GciPublicModels.GciLoginResult> LoginAsync(
|
|
int slot,
|
|
CancellationToken token = default)
|
|
{
|
|
return gciExternalInterface.LoginOneSlotAsync(slot, token);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Disconnects/logs out from the meter assigned to the requested slot.
|
|
///
|
|
/// Trace:
|
|
/// GciBridge.DisconnectAsync()
|
|
/// -> InterfaceOutsideToGCI.DisconnectAsync()
|
|
/// -> InterfaceGCIToLaatzen.DisconnectAsync()
|
|
/// -> per-slot GCI worker
|
|
/// -> GenesisMeter.Logout()
|
|
/// -> GenesisMeter.DisposeMeter()
|
|
/// -> worker disposal
|
|
/// </summary>
|
|
/// <param name="slotId">Slot number.</param>
|
|
/// <param name="token">Cancellation token.</param>
|
|
/// <returns>Disconnect operation result.</returns>
|
|
public async Task<GciPublicModels.GciDisconnectResult> DisconnectAsync(
|
|
int slotId,
|
|
CancellationToken token = default)
|
|
{
|
|
log.InfoFormat("{0}: DisconnectAsync({1}) invoked.", Name, slotId);
|
|
|
|
EnsureExternalInterface();
|
|
|
|
if (slotId <= 0)
|
|
throw new ArgumentException("Invalid slot id.");
|
|
|
|
var result = await gciExternalInterface.DisconnectAsync(slotId, token);
|
|
|
|
log.InfoFormat("{0}: DisconnectAsync({1}) invoked. Result={2}", Name, slotId, result);
|
|
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Sets password to meter in given slot.
|
|
///
|
|
/// Trace:
|
|
/// GciBridge.SetPasswordAsync()
|
|
/// -> InterfaceOutsideToGCI.SetPasswordAsync()
|
|
/// -> InterfaceGCIToLaatzen.SetMeterPasswordAsync()
|
|
/// -> per-slot GCI worker
|
|
/// -> GenesisMeter.Password = password
|
|
/// </summary>
|
|
public async Task<GciPublicModels.GciSetPasswordResult> SetPasswordAsync(
|
|
int slotId,
|
|
string password,
|
|
CancellationToken token = default)
|
|
{
|
|
EnsureExternalInterface();
|
|
|
|
if (slotId <= 0)
|
|
throw new ArgumentException("Invalid slot id.");
|
|
|
|
if (string.IsNullOrWhiteSpace(password))
|
|
throw new ArgumentException("Password is empty.");
|
|
|
|
GciPublicModels.GciSetPasswordResult result =
|
|
await gciExternalInterface.SetPasswordAsync(slotId, password, token);
|
|
|
|
log.InfoFormat("{0}: SetPasswordAsync({1}) invoked. Result={2}", Name, slotId, result);
|
|
|
|
return result;
|
|
}
|
|
|
|
public async Task<GciPublicModels.RegisterReadResult> ReadRegisterAsync(
|
|
int slotId,
|
|
string registerName,
|
|
CancellationToken token = default)
|
|
{
|
|
EnsureExternalInterface();
|
|
|
|
if (slotId <= 0)
|
|
throw new ArgumentException("Invalid slot id.");
|
|
|
|
if (string.IsNullOrWhiteSpace(registerName))
|
|
throw new ArgumentException("Register name is empty.");
|
|
|
|
var result = await gciExternalInterface.ReadRegisterAsync(slotId, registerName, token);
|
|
|
|
log.InfoFormat("{0}: ReadRegisterAsync({1}, {2}) invoked. Result={3}",
|
|
Name, slotId, registerName, result);
|
|
|
|
return result;
|
|
}
|
|
|
|
public async Task<GciPublicModels.RegisterWriteResult> WriteRegisterAsync(
|
|
int slotId,
|
|
string registerName,
|
|
object value,
|
|
bool storeToDevice = false,
|
|
bool refreshSystemState = false,
|
|
CancellationToken token = default)
|
|
{
|
|
EnsureExternalInterface();
|
|
|
|
if (slotId <= 0)
|
|
throw new ArgumentException("Invalid slot id.");
|
|
|
|
if (string.IsNullOrWhiteSpace(registerName))
|
|
throw new ArgumentException("Register name is empty.");
|
|
|
|
var result = await gciExternalInterface.WriteRegisterAsync(
|
|
slotId,
|
|
registerName,
|
|
value,
|
|
storeToDevice,
|
|
refreshSystemState,
|
|
token);
|
|
|
|
log.InfoFormat("{0}: WriteRegisterAsync({1}, {2}, {3}) invoked. Result={4}",
|
|
Name, slotId, registerName, value, result);
|
|
|
|
return result;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region ======================================= UDSR Public Interface =======================================
|
|
|
|
/// <summary>
|
|
/// Reads password data from UniDataStorageReader by PCB ID.
|
|
///
|
|
/// Trace:
|
|
/// GciBridge.GetPasswordAsync()
|
|
/// -> UniDataStorageReader.Reader.GetDataFromStorageByParameterAsync()
|
|
/// -> Reader queue/lock
|
|
/// -> Reader.GetDataFromStorageByParameter()
|
|
/// -> selected storage reader by configuration
|
|
/// -> DatabaseReader.GetData() / RestApiReader.GetData() / JsonReader.GetData() / CsvReader.GetData()
|
|
/// </summary>
|
|
/// <param name="pcbId">PCB ID used as query parameter.</param>
|
|
/// <param name="token">Cancellation token.</param>
|
|
/// <returns>Password lookup result.</returns>
|
|
public async Task<UdsPasswordResult> GetPasswordAsync(
|
|
string pcbId,
|
|
CancellationToken token = default)
|
|
{
|
|
EnsureReader();
|
|
|
|
if (string.IsNullOrWhiteSpace(pcbId))
|
|
throw new ArgumentException("PCB ID is empty.", nameof(pcbId));
|
|
|
|
try
|
|
{
|
|
UDSRPublicModels.DataQuery query = CreatePasswordQuery(pcbId);
|
|
|
|
object data = await reader.GetDataFromStorageByParameterAsync(query, token);
|
|
|
|
string password = ExtractPassword(data);
|
|
|
|
return new UdsPasswordResult
|
|
{
|
|
Success = !string.IsNullOrWhiteSpace(password),
|
|
PcbId = pcbId,
|
|
Password = password,
|
|
Message = !string.IsNullOrWhiteSpace(password)
|
|
? "Password found."
|
|
: "Password was not found."
|
|
};
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
log.Error("GetPasswordAsync failed.", ex);
|
|
|
|
return new UdsPasswordResult
|
|
{
|
|
Success = false,
|
|
PcbId = pcbId,
|
|
Password = null,
|
|
Message = ex.Message
|
|
};
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
#region ======================================= Helpers =======================================
|
|
private UDSRPublicModels.DataQuery CreatePasswordQuery(string pcbId)
|
|
{
|
|
var query = new UDSRPublicModels.DataQuery();
|
|
query.QueryParams.Add(pcbId);
|
|
return query;
|
|
}
|
|
|
|
private string ExtractPassword(object data)
|
|
{
|
|
if (data == null)
|
|
return null;
|
|
|
|
if (data is string str)
|
|
return str;
|
|
|
|
if (data is DatabaseSearchResult result)
|
|
{
|
|
if (!result.Found)
|
|
return null;
|
|
|
|
if (result.Values != null &&
|
|
result.Values.TryGetValue("Password", out var value))
|
|
{
|
|
return value?.ToString();
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
// fallback
|
|
return data.ToString();
|
|
}
|
|
#endregion
|
|
|
|
public List<string> GetAllRegisterNames()
|
|
{
|
|
EnsureExternalInterface();
|
|
return gciExternalInterface.GetAllRegisterNames();
|
|
}
|
|
}
|
|
} |