Upgrade (develop) - GCI - GciBridge - big change
This commit is contained in:
@@ -0,0 +1,312 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using static GenesisCordonelInterface.API.InterfaceOutsideToGCI;
|
||||||
|
using static Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore.GenesisMeter;
|
||||||
|
using Xylem.Common.Hardware.Interfaces.Ports.PortCore;
|
||||||
|
|
||||||
|
namespace GenesisCordonelInterface.API
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Public data contract layer for the Genesis Cordonel Interface (GCI).
|
||||||
|
///
|
||||||
|
/// This class defines all Data Transfer Objects (DTOs) that are exposed
|
||||||
|
/// to external consumers (e.g. TBF, UI, or other integration layers).
|
||||||
|
///
|
||||||
|
/// Responsibilities:
|
||||||
|
/// - Provide stable, dependency-free models for external usage
|
||||||
|
/// - Decouple internal GCI implementation (GenesisMeter, Xylem libraries)
|
||||||
|
/// from external systems
|
||||||
|
/// - Define request/response contracts for all supported operations
|
||||||
|
/// - Contain mapping methods between public DTOs and internal domain models
|
||||||
|
///
|
||||||
|
/// Architecture:
|
||||||
|
/// External world (TBF / UI)
|
||||||
|
/// ↓
|
||||||
|
/// GciPublicModels (this layer)
|
||||||
|
/// ↓
|
||||||
|
/// Internal GCI API (InterfaceGCIToLaatzen, GenesisMeter, etc.)
|
||||||
|
///
|
||||||
|
/// Notes:
|
||||||
|
/// - Public models must NOT expose internal types (e.g. GenesisMeter, IPort, etc.)
|
||||||
|
/// - All mapping between internal and external representations must be done here
|
||||||
|
/// - DTOs are designed to be simple, serializable, and stable over time
|
||||||
|
/// - Any change in internal implementation should not affect these models
|
||||||
|
///
|
||||||
|
/// Pattern:
|
||||||
|
/// Each operation follows a consistent structure:
|
||||||
|
/// Request → Operation → Result
|
||||||
|
///
|
||||||
|
/// Example:
|
||||||
|
/// GciInitSlotRequest → InitSlot → GciInitSlotResult
|
||||||
|
/// GetSlot → GciSlotInfo
|
||||||
|
/// GetPcbId → GciGetPcbIdResult
|
||||||
|
///
|
||||||
|
/// This layer acts as a boundary between domain logic and integration logic.
|
||||||
|
/// </summary>
|
||||||
|
public class GciPublicModels
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Public DTOs exposed to external systems.
|
||||||
|
/// These models represent the contract of the GCI API.
|
||||||
|
/// They must remain stable and independent of internal implementation.
|
||||||
|
/// </summary>
|
||||||
|
#region ================================== PUBLIC MODELS ===========================================
|
||||||
|
|
||||||
|
public class GciSlotInfo
|
||||||
|
{
|
||||||
|
public int SlotId { get; set; }
|
||||||
|
|
||||||
|
public bool Exists { get; set; }
|
||||||
|
public bool Success { get; set; }
|
||||||
|
public string Message { get; set; }
|
||||||
|
public string PcbId { get; set; }
|
||||||
|
|
||||||
|
public GciConfigSource ConfigSource { get; set; }
|
||||||
|
public GciPasswordSource PasswordSource { get; set; }
|
||||||
|
|
||||||
|
public GciPortConfig RequestPort { get; set; }
|
||||||
|
public GciPortConfig StreamingPort { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Result
|
||||||
|
{
|
||||||
|
public int SlotId { get; set; }
|
||||||
|
public bool Success { get; set; }
|
||||||
|
public string Message { get; set; }
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return string.Format(
|
||||||
|
"SlotId={0}, Success={1}, Message={2}",
|
||||||
|
SlotId,
|
||||||
|
Success,
|
||||||
|
Message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum GciPasswordSource
|
||||||
|
{
|
||||||
|
RestApi = 0,
|
||||||
|
OfflineFile = 1,
|
||||||
|
InterfaceInputPassword = 2,
|
||||||
|
}
|
||||||
|
public enum GciConfigSource
|
||||||
|
{
|
||||||
|
FileConfig = 0,
|
||||||
|
InterfaceInputConfig = 1,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Collection of port settings
|
||||||
|
/// </summary>
|
||||||
|
public class GciPortConfig
|
||||||
|
{
|
||||||
|
public string PortName { get; set; }
|
||||||
|
public string Type { get; set; }
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return string.Format("PortName={0}, Type={1}", PortName, Type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class GciInitSlotRequest
|
||||||
|
{
|
||||||
|
public int SlotId { get; set; }
|
||||||
|
public GciConfigSource ConfigSource { get; set; }
|
||||||
|
public GciPasswordSource PasswordSource { get; set; }
|
||||||
|
public GciPortConfig RequestPort { get; set; }
|
||||||
|
public GciPortConfig StreamingPort { get; set; }
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return string.Format(
|
||||||
|
"SlotId={0}, GciConfigSource={1}, PasswordSource={2}, RequestPort={3}, StreamingPort={4}",
|
||||||
|
SlotId,
|
||||||
|
ConfigSource,
|
||||||
|
PasswordSource,
|
||||||
|
RequestPort,
|
||||||
|
StreamingPort);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class GciInitSlotResult
|
||||||
|
{
|
||||||
|
public int SlotId { get; set; }
|
||||||
|
|
||||||
|
public bool Success { get; set; }
|
||||||
|
|
||||||
|
public string Message { get; set; }
|
||||||
|
|
||||||
|
public string PcbId { get; set; }
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return string.Format(
|
||||||
|
"SlotId={0}, Success={1}, Message={2}, PcbId={3}",
|
||||||
|
SlotId,
|
||||||
|
Success,
|
||||||
|
Message,
|
||||||
|
PcbId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class GciCleanSlotsResult
|
||||||
|
{
|
||||||
|
public bool Success { get; set; }
|
||||||
|
public string Message { get; set; }
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return string.Format(
|
||||||
|
"Success={0}, Message={1}",
|
||||||
|
Success,
|
||||||
|
Message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class GciGetPcbIdResult
|
||||||
|
{
|
||||||
|
public int SlotId { get; set; }
|
||||||
|
|
||||||
|
public bool Success { get; set; }
|
||||||
|
|
||||||
|
public string PcbId { get; set; }
|
||||||
|
|
||||||
|
public string Message { get; set; }
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return string.Format(
|
||||||
|
"SlotId={0}, Success={1}, PcbId={2}, Message={3}",
|
||||||
|
SlotId,
|
||||||
|
Success,
|
||||||
|
PcbId,
|
||||||
|
Message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public class GciConnectResult
|
||||||
|
{
|
||||||
|
public int SlotId { get; set; }
|
||||||
|
public bool Success { get; set; }
|
||||||
|
public string PcbId { get; set; }
|
||||||
|
public bool IsLoggedOn { get; set; }
|
||||||
|
public string FwVersion { get; set; }
|
||||||
|
public string InterfaceVersion { get; set; }
|
||||||
|
public bool InterfaceSupportsFwVersion { get; set; }
|
||||||
|
public List<GciRegisterSnapshot> Registers { get; set; } = new List<GciRegisterSnapshot>();
|
||||||
|
public string Message { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class GciRegisterSnapshot
|
||||||
|
{
|
||||||
|
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 class GciDisconnectResult
|
||||||
|
{
|
||||||
|
public int SlotId { get; set; }
|
||||||
|
public bool Success { get; set; }
|
||||||
|
public string Message { get; set; }
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return string.Format(
|
||||||
|
"SlotId={0}, Success={1}, Message={2}",
|
||||||
|
SlotId,
|
||||||
|
Success,
|
||||||
|
Message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Mapping methods between public DTOs and internal GCI models.
|
||||||
|
/// Ensures separation between external contracts and internal domain objects.
|
||||||
|
/// </summary>
|
||||||
|
#region ================================== OUTERN/INTERN and back models mapping ==================================
|
||||||
|
public static PasswordSource MapPasswordSource(GciPasswordSource src)
|
||||||
|
{
|
||||||
|
return (PasswordSource)src;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ConfigSource MapConfigSource(GciConfigSource src)
|
||||||
|
{
|
||||||
|
return (ConfigSource)src;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Xylem.Common.Hardware.Interfaces.Ports.PortCore.PortConfig? MapPort(GciPortConfig port)
|
||||||
|
{
|
||||||
|
if (port == null)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
Xylem.Common.Hardware.Interfaces.Ports.PortCore.PortConfig result = new Xylem.Common.Hardware.Interfaces.Ports.PortCore.PortConfig();
|
||||||
|
|
||||||
|
result.PortName = port.PortName;
|
||||||
|
result.Type = port.Type;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static GciInitSlotResult MapInitResult(GciInitSlotResult result)
|
||||||
|
{
|
||||||
|
if (result == null)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
return new GciInitSlotResult
|
||||||
|
{
|
||||||
|
SlotId = result.SlotId,
|
||||||
|
Success = result.Success,
|
||||||
|
Message = result.Message
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static GciPasswordSource MapPasswordSourceBack(PasswordSource src)
|
||||||
|
{
|
||||||
|
return (GciPasswordSource)src;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static GciConfigSource MapConfigSourceBack(ConfigSource src)
|
||||||
|
{
|
||||||
|
return (GciConfigSource)src;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static GciPortConfig MapPortBack(PortConfig? port)
|
||||||
|
{
|
||||||
|
if (!port.HasValue)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
PortConfig value = port.Value;
|
||||||
|
|
||||||
|
return new GciPortConfig
|
||||||
|
{
|
||||||
|
PortName = value.PortName,
|
||||||
|
Type = value.Type
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static GciPortConfig MapPortBack(IPort port)
|
||||||
|
{
|
||||||
|
if (port == null)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
return new GciPortConfig
|
||||||
|
{
|
||||||
|
PortName = port.GetPortName(),
|
||||||
|
Type = port.GetType().Name
|
||||||
|
};
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,15 +1,16 @@
|
|||||||
using System;
|
using GenesisCordonelInterface.Core.Threading;
|
||||||
|
using NLog;
|
||||||
|
using System;
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using GenesisCordonelInterface.Core.Threading;
|
|
||||||
using NLog;
|
|
||||||
using Xylem.Common.Hardware.Interfaces.Ports.PortCore;
|
using Xylem.Common.Hardware.Interfaces.Ports.PortCore;
|
||||||
using Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore;
|
using Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore;
|
||||||
using Xylem.Common.Hardware.WaterMeter.Genesis.Registers;
|
using Xylem.Common.Hardware.WaterMeter.Genesis.Registers;
|
||||||
using Xylem.Common.Hardware.WaterMeter.WaterMeterCore;
|
using Xylem.Common.Hardware.WaterMeter.WaterMeterCore;
|
||||||
|
using static GenesisCordonelInterface.API.GciPublicModels;
|
||||||
using static Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore.GenesisMeter;
|
using static Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore.GenesisMeter;
|
||||||
|
|
||||||
namespace GenesisCordonelInterface.API
|
namespace GenesisCordonelInterface.API
|
||||||
@@ -31,7 +32,7 @@ namespace GenesisCordonelInterface.API
|
|||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Worker
|
#region ================================== Worker ==================================
|
||||||
|
|
||||||
private ApiWorker GetWorker(int slot)
|
private ApiWorker GetWorker(int slot)
|
||||||
{
|
{
|
||||||
@@ -43,7 +44,7 @@ namespace GenesisCordonelInterface.API
|
|||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Worker Debug
|
#region ================================== Worker Debug ==================================
|
||||||
public class WorkerDebugStatus
|
public class WorkerDebugStatus
|
||||||
{
|
{
|
||||||
public int Slot { get; set; }
|
public int Slot { get; set; }
|
||||||
@@ -73,7 +74,7 @@ namespace GenesisCordonelInterface.API
|
|||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region MeterBatch Debug
|
#region ================================== MeterBatch Debug ==================================
|
||||||
public class MeterBatchDebugStatus
|
public class MeterBatchDebugStatus
|
||||||
{
|
{
|
||||||
public int Slot { get; set; }
|
public int Slot { get; set; }
|
||||||
@@ -134,7 +135,7 @@ namespace GenesisCordonelInterface.API
|
|||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Helpers
|
#region ================================== Helpers ==================================
|
||||||
|
|
||||||
private GenesisMeter GetMeter(int slot)
|
private GenesisMeter GetMeter(int slot)
|
||||||
{
|
{
|
||||||
@@ -178,40 +179,32 @@ namespace GenesisCordonelInterface.API
|
|||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region INIT
|
#region ================================== INIT ==================================
|
||||||
|
|
||||||
public class InitResult
|
public Task<GciPublicModels.GciInitSlotResult> InitOneMeterFromExternAsync(
|
||||||
|
int slot,
|
||||||
|
ConfigSource cfg,
|
||||||
|
PasswordSource pwd,
|
||||||
|
PortConfig? req,
|
||||||
|
PortConfig? str,
|
||||||
|
CancellationToken token = default)
|
||||||
{
|
{
|
||||||
public bool Success { get; set; }
|
return GetWorker(slot).RunAsync(() => InitOneMeterFromExtern(slot, cfg, pwd, req, str), token);
|
||||||
public int Slot { get; set; }
|
|
||||||
public string ErrorMessage { get; set; }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task<InitResult> InitOneMeterFromExternAsync(
|
public GciPublicModels.GciInitSlotResult InitOneMeterFromExtern(
|
||||||
int slot,
|
int slot,
|
||||||
ConfigSource cfg,
|
ConfigSource cfg,
|
||||||
PasswordSource pwd,
|
PasswordSource pwd,
|
||||||
PortConfig? req,
|
PortConfig? req,
|
||||||
PortConfig? str,
|
PortConfig? str)
|
||||||
CancellationToken token = default)
|
|
||||||
{
|
|
||||||
return GetWorker(slot).RunAsync(() =>
|
|
||||||
InitOneMeterFromExtern(slot, cfg, pwd, req, str), token);
|
|
||||||
}
|
|
||||||
|
|
||||||
public InitResult InitOneMeterFromExtern(
|
|
||||||
int slot,
|
|
||||||
ConfigSource cfg,
|
|
||||||
PasswordSource pwd,
|
|
||||||
PortConfig? req,
|
|
||||||
PortConfig? str)
|
|
||||||
{
|
{
|
||||||
const string operation = nameof(InitOneMeterFromExtern);
|
const string operation = nameof(InitOneMeterFromExtern);
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
LogInfo(operation,
|
LogInfo(operation,
|
||||||
$"Start. Slot={slot}, ConfigSource={cfg}, PasswordSource={pwd}, " +
|
$"Start. Slot={slot}, GciConfigSource={cfg}, PasswordSource={pwd}, " +
|
||||||
$"RequestPort={(req.HasValue ? req.Value.PortName.ToString() : "<empty>")}, " +
|
$"RequestPort={(req.HasValue ? req.Value.PortName.ToString() : "<empty>")}, " +
|
||||||
$"StreamingPort={(str.HasValue ? str.Value.PortName.ToString() : "<empty>")}");
|
$"StreamingPort={(str.HasValue ? str.Value.PortName.ToString() : "<empty>")}");
|
||||||
|
|
||||||
@@ -227,24 +220,128 @@ namespace GenesisCordonelInterface.API
|
|||||||
|
|
||||||
LogInfo(operation, $"Success. Slot={slot}, MeterBatchCount={_meterBatch.ListOfMeters.Count}");
|
LogInfo(operation, $"Success. Slot={slot}, MeterBatchCount={_meterBatch.ListOfMeters.Count}");
|
||||||
|
|
||||||
return new InitResult { Success = true, Slot = slot };
|
return new GciPublicModels.GciInitSlotResult { Success = true, SlotId = slot };
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
LogError(operation, ex);
|
LogError(operation, ex);
|
||||||
|
|
||||||
return new InitResult
|
return new GciPublicModels.GciInitSlotResult
|
||||||
{
|
{
|
||||||
Success = false,
|
Success = false,
|
||||||
Slot = slot,
|
SlotId = slot,
|
||||||
ErrorMessage = ex.Message
|
Message = ex.Message
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<GciPublicModels.GciSlotInfo> GetOneMeterInfo(
|
||||||
|
int slot,
|
||||||
|
CancellationToken token = default)
|
||||||
|
{
|
||||||
|
return GetWorker(slot).RunAsync(() => GetOneMeterInfo(slot), token);
|
||||||
|
}
|
||||||
|
|
||||||
|
public GciPublicModels.GciSlotInfo GetOneMeterInfo(int slotId)
|
||||||
|
{
|
||||||
|
const string operation = nameof(GetOneMeterInfo);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
LogInfo(operation, $"Start. Slot={slotId}");
|
||||||
|
|
||||||
|
var meter = _meterBatch.ListOfMeters
|
||||||
|
.OfType<GenesisMeter>()
|
||||||
|
.FirstOrDefault(m => m.Slot == slotId);
|
||||||
|
|
||||||
|
if (meter == null)
|
||||||
|
{
|
||||||
|
return new GciPublicModels.GciSlotInfo
|
||||||
|
{
|
||||||
|
SlotId = slotId,
|
||||||
|
Success = true,
|
||||||
|
Exists = false,
|
||||||
|
Message = "Slot is empty."
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return new GciPublicModels.GciSlotInfo
|
||||||
|
{
|
||||||
|
SlotId = slotId,
|
||||||
|
Success = true,
|
||||||
|
Exists = true,
|
||||||
|
Message = "Slot found.",
|
||||||
|
|
||||||
|
// PcbId = meter.PcbId,
|
||||||
|
|
||||||
|
ConfigSource = GciPublicModels.MapConfigSourceBack(meter.useConfigSource),
|
||||||
|
PasswordSource = GciPublicModels.MapPasswordSourceBack(meter.usePasswordSource),
|
||||||
|
|
||||||
|
RequestPort = GciPublicModels.MapPortBack(meter.RequestPort),
|
||||||
|
StreamingPort = GciPublicModels.MapPortBack(meter.StreamingPort)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
LogError(operation, ex);
|
||||||
|
|
||||||
|
return new GciPublicModels.GciSlotInfo
|
||||||
|
{
|
||||||
|
SlotId = slotId,
|
||||||
|
Success = false,
|
||||||
|
Exists = false,
|
||||||
|
Message = ex.Message
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<GciPublicModels.GciCleanSlotsResult> CleanSlotsAsync(
|
||||||
|
CancellationToken token = default)
|
||||||
|
{
|
||||||
|
return Task.Run(() => CleanSlots(), token);
|
||||||
|
}
|
||||||
|
|
||||||
|
public GciPublicModels.GciCleanSlotsResult CleanSlots()
|
||||||
|
{
|
||||||
|
const string operation = nameof(CleanSlots);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
LogInfo(operation, "Start.");
|
||||||
|
|
||||||
|
_meterBatch.ListOfMeters.Clear();
|
||||||
|
_selectedSlots.Clear();
|
||||||
|
|
||||||
|
foreach (var worker in _workers.Values)
|
||||||
|
{
|
||||||
|
worker.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
_workers.Clear();
|
||||||
|
|
||||||
|
LogInfo(operation, "Success. Meter batch, selected slots and workers cleared.");
|
||||||
|
|
||||||
|
return new GciPublicModels.GciCleanSlotsResult
|
||||||
|
{
|
||||||
|
Success = true,
|
||||||
|
Message = "Slots cleaned."
|
||||||
|
};
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
LogError(operation, ex);
|
||||||
|
|
||||||
|
return new GciPublicModels.GciCleanSlotsResult
|
||||||
|
{
|
||||||
|
Success = false,
|
||||||
|
Message = ex.Message
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region PORT DETECTION
|
#region ================================== PORT DETECTION ==================================
|
||||||
|
|
||||||
public class PortDetectionResult
|
public class PortDetectionResult
|
||||||
{
|
{
|
||||||
@@ -361,45 +458,16 @@ namespace GenesisCordonelInterface.API
|
|||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region CONNECT
|
#region ================================== CONNECT ==================================
|
||||||
|
|
||||||
public class ConnectResult
|
public Task<GciPublicModels.GciConnectResult> ConnectOneSlotAsync(int slot, CancellationToken token = default)
|
||||||
{
|
{
|
||||||
public bool Success { get; set; }
|
return GetWorker(slot).RunAsync(() => ConnectOneSlot(slot), token);
|
||||||
public int Slot { get; set; }
|
|
||||||
public string PcbId { get; set; }
|
|
||||||
public bool IsLoggedOn { get; set; }
|
|
||||||
|
|
||||||
public string FwVersion { get; set; }
|
|
||||||
public string InterfaceVersion { get; set; }
|
|
||||||
public bool InterfaceSupportsFwVersion { get; set; }
|
|
||||||
|
|
||||||
public List<RegisterSnapshot> Registers { get; set; } = new List<RegisterSnapshot>();
|
|
||||||
|
|
||||||
public string ErrorMessage { get; set; }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public class RegisterSnapshot
|
public GciPublicModels.GciConnectResult ConnectOneSlot(int slot)
|
||||||
{
|
{
|
||||||
public string Name { get; set; }
|
const string operation = nameof(ConnectOneSlot);
|
||||||
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 Task<ConnectResult> ConnectOneMeterAsync(int slot, CancellationToken token = default)
|
|
||||||
{
|
|
||||||
return GetWorker(slot).RunAsync(() => ConnectOneMeter(slot), token);
|
|
||||||
}
|
|
||||||
|
|
||||||
public ConnectResult ConnectOneMeter(int slot)
|
|
||||||
{
|
|
||||||
const string operation = nameof(ConnectOneMeter);
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -413,18 +481,18 @@ namespace GenesisCordonelInterface.API
|
|||||||
{
|
{
|
||||||
LogInfo(operation, $"Failed. Slot={slot}, Reason=Login failed.");
|
LogInfo(operation, $"Failed. Slot={slot}, Reason=Login failed.");
|
||||||
|
|
||||||
return new ConnectResult
|
return new GciPublicModels.GciConnectResult
|
||||||
{
|
{
|
||||||
Success = false,
|
Success = false,
|
||||||
Slot = slot,
|
SlotId = slot,
|
||||||
ErrorMessage = "Login failed."
|
Message = "Login failed."
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
var result = new ConnectResult
|
var result = new GciPublicModels.GciConnectResult
|
||||||
{
|
{
|
||||||
Success = true,
|
Success = true,
|
||||||
Slot = slot,
|
SlotId = slot,
|
||||||
PcbId = meter.PcbId,
|
PcbId = meter.PcbId,
|
||||||
IsLoggedOn = true,
|
IsLoggedOn = true,
|
||||||
FwVersion = meter.FwVersion,
|
FwVersion = meter.FwVersion,
|
||||||
@@ -444,25 +512,25 @@ namespace GenesisCordonelInterface.API
|
|||||||
{
|
{
|
||||||
LogError(operation, ex);
|
LogError(operation, ex);
|
||||||
|
|
||||||
return new ConnectResult
|
return new GciPublicModels.GciConnectResult
|
||||||
{
|
{
|
||||||
Success = false,
|
Success = false,
|
||||||
Slot = slot,
|
SlotId = slot,
|
||||||
ErrorMessage = ex.Message
|
Message = ex.Message
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<RegisterSnapshot> BuildRegisters(GenesisMeter meter)
|
private List<GciPublicModels.GciRegisterSnapshot> BuildRegisters(GenesisMeter meter)
|
||||||
{
|
{
|
||||||
var list = new List<RegisterSnapshot>();
|
var list = new List<GciRegisterSnapshot>();
|
||||||
|
|
||||||
foreach (var item in meter.GetRegistersDic())
|
foreach (var item in meter.GetRegistersDic())
|
||||||
{
|
{
|
||||||
var from = item.Key.RegisterDetail.Version.First?.ToString() ?? "-";
|
var from = item.Key.RegisterDetail.Version.First?.ToString() ?? "-";
|
||||||
var to = item.Key.RegisterDetail.Version.Last?.ToString() ?? "-";
|
var to = item.Key.RegisterDetail.Version.Last?.ToString() ?? "-";
|
||||||
|
|
||||||
list.Add(new RegisterSnapshot
|
list.Add(new GciRegisterSnapshot
|
||||||
{
|
{
|
||||||
Name = item.Key.GetIdent(),
|
Name = item.Key.GetIdent(),
|
||||||
Type = item.Key.DataType.Name,
|
Type = item.Key.DataType.Name,
|
||||||
@@ -481,14 +549,72 @@ namespace GenesisCordonelInterface.API
|
|||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region PCB
|
#region ================================== DISCONNECT ==================================
|
||||||
|
|
||||||
public Task<string> GetPcbIdAsync(int slot, CancellationToken token = default(CancellationToken))
|
public Task<GciPublicModels.GciDisconnectResult> DisconnectAsync(
|
||||||
|
int slot,
|
||||||
|
CancellationToken token = default)
|
||||||
|
{
|
||||||
|
return GetWorker(slot).RunAsync(() => Disconnect(slot), token);
|
||||||
|
}
|
||||||
|
|
||||||
|
public GciPublicModels.GciDisconnectResult Disconnect(int slot)
|
||||||
|
{
|
||||||
|
const string operation = nameof(Disconnect);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
LogInfo(operation, $"Start. Slot={slot}");
|
||||||
|
|
||||||
|
var meter = GetMeter(slot);
|
||||||
|
|
||||||
|
if (meter.IsLoggedOn)
|
||||||
|
meter.Logout();
|
||||||
|
|
||||||
|
meter.DisposeMeter();
|
||||||
|
|
||||||
|
LogInfo(operation, $"Success. Slot={slot}");
|
||||||
|
|
||||||
|
return new GciPublicModels.GciDisconnectResult
|
||||||
|
{
|
||||||
|
SlotId = slot,
|
||||||
|
Success = true,
|
||||||
|
Message = "Disconnected successfully."
|
||||||
|
};
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
LogError(operation, ex);
|
||||||
|
|
||||||
|
return new GciPublicModels.GciDisconnectResult
|
||||||
|
{
|
||||||
|
SlotId = slot,
|
||||||
|
Success = false,
|
||||||
|
Message = ex.Message
|
||||||
|
};
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
if (_workers.TryRemove(slot, out var worker))
|
||||||
|
{
|
||||||
|
worker.Dispose();
|
||||||
|
LogInfo(operation, $"Worker disposed. Slot={slot}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region ================================== PCB ==================================
|
||||||
|
|
||||||
|
public Task<GciPublicModels.GciGetPcbIdResult> GetPcbIdAsync(
|
||||||
|
int slot,
|
||||||
|
CancellationToken token = default(CancellationToken))
|
||||||
{
|
{
|
||||||
return GetWorker(slot).RunAsync(() => GetPcbId(slot), token, "GetPcbId");
|
return GetWorker(slot).RunAsync(() => GetPcbId(slot), token, "GetPcbId");
|
||||||
}
|
}
|
||||||
|
|
||||||
public string GetPcbId(int slot)
|
public GciPublicModels.GciGetPcbIdResult GetPcbId(int slot)
|
||||||
{
|
{
|
||||||
const string operation = nameof(GetPcbId);
|
const string operation = nameof(GetPcbId);
|
||||||
|
|
||||||
@@ -507,19 +633,34 @@ namespace GenesisCordonelInterface.API
|
|||||||
|
|
||||||
LogInfo(operation, $"Finish. Slot={slot}, PcbId={pcbId ?? "<empty>"}");
|
LogInfo(operation, $"Finish. Slot={slot}, PcbId={pcbId ?? "<empty>"}");
|
||||||
|
|
||||||
return pcbId;
|
return new GciPublicModels.GciGetPcbIdResult
|
||||||
|
{
|
||||||
|
SlotId = slot,
|
||||||
|
Success = !string.IsNullOrWhiteSpace(pcbId),
|
||||||
|
PcbId = pcbId,
|
||||||
|
Message = !string.IsNullOrWhiteSpace(pcbId)
|
||||||
|
? "PCB ID read successfully."
|
||||||
|
: "PCB ID is empty."
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
LogError(operation, ex);
|
LogError(operation, ex);
|
||||||
throw;
|
|
||||||
|
return new GciPublicModels.GciGetPcbIdResult
|
||||||
|
{
|
||||||
|
SlotId = slot,
|
||||||
|
Success = false,
|
||||||
|
PcbId = null,
|
||||||
|
Message = ex.Message
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region REGISTER READ
|
#region ================================== REGISTER READ ==================================
|
||||||
|
|
||||||
public class RegisterReadResult
|
public class RegisterReadResult
|
||||||
{
|
{
|
||||||
@@ -573,7 +714,7 @@ namespace GenesisCordonelInterface.API
|
|||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region REGISTER WRITE
|
#region ================================== REGISTER WRITE ==================================
|
||||||
|
|
||||||
public class RegisterWriteResult
|
public class RegisterWriteResult
|
||||||
{
|
{
|
||||||
@@ -700,47 +841,7 @@ namespace GenesisCordonelInterface.API
|
|||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region DISCONNECT
|
#region ================================== PASSWORD ==================================
|
||||||
|
|
||||||
public Task DisconnectAsync(int slot, CancellationToken token = default)
|
|
||||||
{
|
|
||||||
return GetWorker(slot).RunAsync(() => Disconnect(slot), token);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Disconnect(int slot)
|
|
||||||
{
|
|
||||||
const string operation = nameof(Disconnect);
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
LogInfo(operation, $"Start. Slot={slot}");
|
|
||||||
|
|
||||||
var meter = GetMeter(slot);
|
|
||||||
|
|
||||||
if (meter.IsLoggedOn)
|
|
||||||
meter.Logout();
|
|
||||||
|
|
||||||
meter.DisposeMeter();
|
|
||||||
|
|
||||||
LogInfo(operation, $"Success. Slot={slot}");
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
LogError(operation, ex);
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
if (_workers.TryRemove(slot, out var worker))
|
|
||||||
{
|
|
||||||
worker.Dispose();
|
|
||||||
LogInfo(operation, $"Worker disposed. Slot={slot}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region PASSWORD
|
|
||||||
|
|
||||||
public Task<bool> SetMeterPasswordAsync(
|
public Task<bool> SetMeterPasswordAsync(
|
||||||
int slot,
|
int slot,
|
||||||
@@ -776,7 +877,7 @@ namespace GenesisCordonelInterface.API
|
|||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region METER BATCH SETUP
|
#region ================================== METER BATCH SETUP ==================================
|
||||||
// ----------------------------------------------------
|
// ----------------------------------------------------
|
||||||
|
|
||||||
public void ReloadSlotSetup()
|
public void ReloadSlotSetup()
|
||||||
|
|||||||
@@ -1,9 +1,8 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.IO.Ports;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Xylem.Common.Hardware.Interfaces.Ports.PortCore;
|
|
||||||
using static Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore.GenesisMeter;
|
|
||||||
|
|
||||||
namespace GenesisCordonelInterface.API
|
namespace GenesisCordonelInterface.API
|
||||||
{
|
{
|
||||||
@@ -15,10 +14,6 @@ namespace GenesisCordonelInterface.API
|
|||||||
{
|
{
|
||||||
private readonly InterfaceGCIToLaatzen _innerMeterAPI;
|
private readonly InterfaceGCIToLaatzen _innerMeterAPI;
|
||||||
|
|
||||||
private readonly Dictionary<int, PortConfig> _requestPorts = new Dictionary<int, PortConfig>();
|
|
||||||
private readonly Dictionary<int, PortConfig> _streamingPorts = new Dictionary<int, PortConfig>();
|
|
||||||
private readonly object _portLock = new object();
|
|
||||||
|
|
||||||
public event Action<List<InterfaceGCIToLaatzen.MeterBatchDebugStatus>> MeterBatchStatusChanged;
|
public event Action<List<InterfaceGCIToLaatzen.MeterBatchDebugStatus>> MeterBatchStatusChanged;
|
||||||
|
|
||||||
public InterfaceOutsideToGCI()
|
public InterfaceOutsideToGCI()
|
||||||
@@ -26,8 +21,7 @@ namespace GenesisCordonelInterface.API
|
|||||||
_innerMeterAPI = new InterfaceGCIToLaatzen();
|
_innerMeterAPI = new InterfaceGCIToLaatzen();
|
||||||
}
|
}
|
||||||
|
|
||||||
#region PORT DETECTION
|
#region ================================== PORT DETECTION ==================================
|
||||||
// ----------------------------------------------------
|
|
||||||
|
|
||||||
public InterfaceGCIToLaatzen.PortDetectionResult DetectStreamingPort(int slot)
|
public InterfaceGCIToLaatzen.PortDetectionResult DetectStreamingPort(int slot)
|
||||||
{
|
{
|
||||||
@@ -61,132 +55,96 @@ namespace GenesisCordonelInterface.API
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region INIT
|
#region ================================== INIT ==================================
|
||||||
// ----------------------------------------------------
|
|
||||||
|
|
||||||
public InterfaceGCIToLaatzen.InitResult InitOneMeterFromExtern(
|
public async Task<GciPublicModels.GciInitSlotResult> InitSlotAsync(GciPublicModels.GciInitSlotRequest request, CancellationToken token = default)
|
||||||
int slot,
|
|
||||||
ConfigSource useConfigSource,
|
|
||||||
PasswordSource usePasswordSource,
|
|
||||||
PortConfig? requestPort,
|
|
||||||
PortConfig? streamingPort)
|
|
||||||
{
|
{
|
||||||
var result = _innerMeterAPI.InitOneMeterFromExtern(
|
if (request == null)
|
||||||
slot,
|
throw new ArgumentNullException(nameof(request));
|
||||||
useConfigSource,
|
|
||||||
usePasswordSource,
|
|
||||||
requestPort,
|
|
||||||
streamingPort);
|
|
||||||
|
|
||||||
RaiseMeterBatchStatusChanged();
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<InterfaceGCIToLaatzen.InitResult> InitOneMeterFromExternAsync(
|
|
||||||
int slot,
|
|
||||||
ConfigSource useConfigSource,
|
|
||||||
PasswordSource usePasswordSource,
|
|
||||||
PortConfig? requestPort,
|
|
||||||
PortConfig? streamingPort,
|
|
||||||
CancellationToken token = default(CancellationToken))
|
|
||||||
{
|
|
||||||
var result = await _innerMeterAPI.InitOneMeterFromExternAsync(
|
var result = await _innerMeterAPI.InitOneMeterFromExternAsync(
|
||||||
slot,
|
request.SlotId,
|
||||||
useConfigSource,
|
GciPublicModels.MapConfigSource(request.ConfigSource),
|
||||||
usePasswordSource,
|
GciPublicModels.MapPasswordSource(request.PasswordSource),
|
||||||
requestPort,
|
GciPublicModels.MapPort(request.RequestPort),
|
||||||
streamingPort,
|
GciPublicModels.MapPort(request.StreamingPort),
|
||||||
token);
|
token);
|
||||||
|
|
||||||
RaiseMeterBatchStatusChanged();
|
RaiseMeterBatchStatusChanged();
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public InterfaceGCIToLaatzen.InitResult InitSlotWithConfiguredPorts(
|
public async Task<GciPublicModels.GciSlotInfo> GetSlotAsync(
|
||||||
int slot,
|
int slotId,
|
||||||
ConfigSource useConfigSource,
|
CancellationToken token = default)
|
||||||
PasswordSource usePasswordSource)
|
|
||||||
{
|
{
|
||||||
return InitOneMeterFromExtern(
|
if (slotId <= 0)
|
||||||
slot,
|
throw new ArgumentException("Invalid slot id.");
|
||||||
useConfigSource,
|
|
||||||
usePasswordSource,
|
var result = await _innerMeterAPI.GetOneMeterInfo(slotId, token);
|
||||||
GetSlotRequestPort(slot),
|
|
||||||
GetSlotStreamingPort(slot));
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task<InterfaceGCIToLaatzen.InitResult> InitSlotWithConfiguredPortsAsync(
|
public async Task<GciPublicModels.GciCleanSlotsResult> CleanSlotsAsync(
|
||||||
int slot,
|
CancellationToken token = default)
|
||||||
ConfigSource useConfigSource,
|
|
||||||
PasswordSource usePasswordSource,
|
|
||||||
CancellationToken token = default(CancellationToken))
|
|
||||||
{
|
{
|
||||||
return InitOneMeterFromExternAsync(
|
var result = await _innerMeterAPI.CleanSlotsAsync(token);
|
||||||
slot,
|
|
||||||
useConfigSource,
|
|
||||||
usePasswordSource,
|
|
||||||
GetSlotRequestPort(slot),
|
|
||||||
GetSlotStreamingPort(slot),
|
|
||||||
token);
|
|
||||||
}
|
|
||||||
|
|
||||||
// ----------------------------------------------------
|
RaiseMeterBatchStatusChanged();
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region CONNECTION
|
#region ================================== CONNECTION ==================================
|
||||||
// ----------------------------------------------------
|
|
||||||
|
|
||||||
public InterfaceGCIToLaatzen.ConnectResult ConnectOneMeter(int slot)
|
public async Task<GciPublicModels.GciConnectResult> ConnectOneSlotAsync(
|
||||||
|
int slot,
|
||||||
|
CancellationToken token = default)
|
||||||
{
|
{
|
||||||
var result = _innerMeterAPI.ConnectOneMeter(slot);
|
GciPublicModels.GciConnectResult result = await _innerMeterAPI.ConnectOneSlotAsync(slot, token);
|
||||||
|
|
||||||
RaiseMeterBatchStatusChanged();
|
RaiseMeterBatchStatusChanged();
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<InterfaceGCIToLaatzen.ConnectResult> ConnectOneMeterAsync(
|
public async Task<GciPublicModels.GciDisconnectResult> DisconnectAsync(
|
||||||
int slot,
|
int slot,
|
||||||
CancellationToken token = default(CancellationToken))
|
CancellationToken token = default)
|
||||||
{
|
{
|
||||||
var result = await _innerMeterAPI.ConnectOneMeterAsync(slot, token);
|
if (slot <= 0)
|
||||||
|
throw new ArgumentException("Invalid slot id.");
|
||||||
|
|
||||||
|
var result = await _innerMeterAPI.DisconnectAsync(slot, token);
|
||||||
|
|
||||||
RaiseMeterBatchStatusChanged();
|
RaiseMeterBatchStatusChanged();
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Disconnect(int slot)
|
|
||||||
{
|
|
||||||
_innerMeterAPI.Disconnect(slot);
|
|
||||||
RaiseMeterBatchStatusChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task DisconnectAsync(
|
|
||||||
int slot,
|
|
||||||
CancellationToken token = default(CancellationToken))
|
|
||||||
{
|
|
||||||
await _innerMeterAPI.DisconnectAsync(slot, token);
|
|
||||||
RaiseMeterBatchStatusChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
// ----------------------------------------------------
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region READ
|
#region ================================== PCB ==================================
|
||||||
|
public async Task<GciPublicModels.GciGetPcbIdResult> GetPcbIdAsync(
|
||||||
|
int slot,
|
||||||
|
CancellationToken token = default)
|
||||||
|
{
|
||||||
|
if (slot <= 0)
|
||||||
|
throw new ArgumentException("Invalid slot id.");
|
||||||
|
|
||||||
|
var result = await _innerMeterAPI.GetPcbIdAsync(slot, token);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region ================================== READ ==================================
|
||||||
// ----------------------------------------------------
|
// ----------------------------------------------------
|
||||||
|
|
||||||
public string GetPcbId(int slot)
|
|
||||||
{
|
|
||||||
return _innerMeterAPI.GetPcbId(slot);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task<string> GetPcbIdAsync(
|
|
||||||
int slot,
|
|
||||||
CancellationToken token = default(CancellationToken))
|
|
||||||
{
|
|
||||||
return _innerMeterAPI.GetPcbIdAsync(slot, token);
|
|
||||||
}
|
|
||||||
|
|
||||||
public InterfaceGCIToLaatzen.RegisterReadResult ReadRegister(
|
public InterfaceGCIToLaatzen.RegisterReadResult ReadRegister(
|
||||||
int slot,
|
int slot,
|
||||||
string registerName)
|
string registerName)
|
||||||
@@ -205,7 +163,7 @@ namespace GenesisCordonelInterface.API
|
|||||||
// ----------------------------------------------------
|
// ----------------------------------------------------
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region WRITE
|
#region ================================== WRITE ==================================
|
||||||
// ----------------------------------------------------
|
// ----------------------------------------------------
|
||||||
|
|
||||||
public async Task<InterfaceGCIToLaatzen.RegisterWriteResult> WriteRegisterAsync(
|
public async Task<InterfaceGCIToLaatzen.RegisterWriteResult> WriteRegisterAsync(
|
||||||
@@ -261,7 +219,7 @@ namespace GenesisCordonelInterface.API
|
|||||||
// ----------------------------------------------------
|
// ----------------------------------------------------
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region DEBUG STATUS
|
#region ================================== DEBUG STATUS ==================================
|
||||||
// ----------------------------------------------------
|
// ----------------------------------------------------
|
||||||
|
|
||||||
public List<InterfaceGCIToLaatzen.WorkerDebugStatus> GetWorkerDebugStatuses()
|
public List<InterfaceGCIToLaatzen.WorkerDebugStatus> GetWorkerDebugStatuses()
|
||||||
@@ -286,7 +244,7 @@ namespace GenesisCordonelInterface.API
|
|||||||
// ----------------------------------------------------
|
// ----------------------------------------------------
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region SLOT SELECTION
|
#region ================================== SLOT SELECTION ==================================
|
||||||
// ----------------------------------------------------
|
// ----------------------------------------------------
|
||||||
|
|
||||||
public void SetSlotSelected(int slot, bool selected)
|
public void SetSlotSelected(int slot, bool selected)
|
||||||
@@ -308,10 +266,10 @@ namespace GenesisCordonelInterface.API
|
|||||||
// ----------------------------------------------------
|
// ----------------------------------------------------
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region SLOT PORT CONFIG
|
#region ================================== SLOT PORT CONFIG ==================================
|
||||||
// ----------------------------------------------------
|
// ----------------------------------------------------
|
||||||
|
|
||||||
public void SetSlotRequestPort(int slot, string portName)
|
/*public void SetSlotRequestPort(int slot, string portName)
|
||||||
{
|
{
|
||||||
lock (_portLock)
|
lock (_portLock)
|
||||||
{
|
{
|
||||||
@@ -321,7 +279,7 @@ namespace GenesisCordonelInterface.API
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_requestPorts[slot] = new PortConfig
|
_requestPorts[slot] = new GciPortConfig
|
||||||
{
|
{
|
||||||
PortName = portName,
|
PortName = portName,
|
||||||
Type = "Serial"
|
Type = "Serial"
|
||||||
@@ -342,7 +300,7 @@ namespace GenesisCordonelInterface.API
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_streamingPorts[slot] = new PortConfig
|
_streamingPorts[slot] = new GciPortConfig
|
||||||
{
|
{
|
||||||
PortName = portName,
|
PortName = portName,
|
||||||
Type = "Serial"
|
Type = "Serial"
|
||||||
@@ -353,11 +311,11 @@ namespace GenesisCordonelInterface.API
|
|||||||
RaiseMeterBatchStatusChanged();
|
RaiseMeterBatchStatusChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
public PortConfig? GetSlotRequestPort(int slot)
|
public GciPortConfig? GetSlotRequestPort(int slot)
|
||||||
{
|
{
|
||||||
lock (_portLock)
|
lock (_portLock)
|
||||||
{
|
{
|
||||||
PortConfig port;
|
GciPortConfig port;
|
||||||
if (_requestPorts.TryGetValue(slot, out port))
|
if (_requestPorts.TryGetValue(slot, out port))
|
||||||
return port;
|
return port;
|
||||||
|
|
||||||
@@ -365,22 +323,22 @@ namespace GenesisCordonelInterface.API
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public PortConfig? GetSlotStreamingPort(int slot)
|
public GciPortConfig? GetSlotStreamingPort(int slot)
|
||||||
{
|
{
|
||||||
lock (_portLock)
|
lock (_portLock)
|
||||||
{
|
{
|
||||||
PortConfig port;
|
GciPortConfig port;
|
||||||
if (_streamingPorts.TryGetValue(slot, out port))
|
if (_streamingPorts.TryGetValue(slot, out port))
|
||||||
return port;
|
return port;
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}*/
|
||||||
|
|
||||||
// ----------------------------------------------------
|
// ----------------------------------------------------
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region METER BATCH SETUP
|
#region ================================== METER BATCH SETUP ==================================
|
||||||
// ----------------------------------------------------
|
// ----------------------------------------------------
|
||||||
|
|
||||||
public void ReloadSlotSetup()
|
public void ReloadSlotSetup()
|
||||||
|
|||||||
@@ -58,6 +58,7 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Include="API\InterfaceOutsideToGCI.cs" />
|
<Compile Include="API\InterfaceOutsideToGCI.cs" />
|
||||||
<Compile Include="API\InterfaceGCIToLaatzen.cs" />
|
<Compile Include="API\InterfaceGCIToLaatzen.cs" />
|
||||||
|
<Compile Include="API\GciPublicModels.cs" />
|
||||||
<Compile Include="Core\Logging\UiLogBus.cs" />
|
<Compile Include="Core\Logging\UiLogBus.cs" />
|
||||||
<Compile Include="Core\Logging\UiTarget.cs" />
|
<Compile Include="Core\Logging\UiTarget.cs" />
|
||||||
<Compile Include="Core\Threading\ApiWorker\ApiWorker.cs" />
|
<Compile Include="Core\Threading\ApiWorker\ApiWorker.cs" />
|
||||||
|
|||||||
@@ -266,13 +266,13 @@ namespace GenesisCordonelInterface.UI.Debug
|
|||||||
|
|
||||||
if (columnName == "RequestPort")
|
if (columnName == "RequestPort")
|
||||||
{
|
{
|
||||||
api.SetSlotRequestPort(slot, port);
|
//api.SetSlotRequestPort(slot, port);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (columnName == "StreamingPort")
|
if (columnName == "StreamingPort")
|
||||||
{
|
{
|
||||||
api.SetSlotStreamingPort(slot, port);
|
//api.SetSlotStreamingPort(slot, port);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -492,7 +492,7 @@ namespace GenesisCordonelInterface.UI.LaatzenAPI_GenesisToolBox
|
|||||||
DisableAllButtons();
|
DisableAllButtons();
|
||||||
_dataTable.Rows.Clear();
|
_dataTable.Rows.Clear();
|
||||||
|
|
||||||
var result = await interfaceToLaatzen.ConnectOneMeterAsync(slotNo);
|
var result = await interfaceToLaatzen.ConnectOneSlotAsync(slotNo);
|
||||||
|
|
||||||
if (result.Success)
|
if (result.Success)
|
||||||
{
|
{
|
||||||
@@ -571,7 +571,7 @@ namespace GenesisCordonelInterface.UI.LaatzenAPI_GenesisToolBox
|
|||||||
lblState.Text = $@"Not Connected to PcbId:{result.PcbId}";
|
lblState.Text = $@"Not Connected to PcbId:{result.PcbId}";
|
||||||
registerGridView.Visible = false;
|
registerGridView.Visible = false;
|
||||||
|
|
||||||
MessageBox.Show(result.ErrorMessage ?? "Connect failed.", @"FAILED", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
MessageBox.Show(result.Message ?? "Connect failed.", @"FAILED", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
@@ -1172,11 +1172,16 @@ namespace GenesisCordonelInterface.UI.LaatzenAPI_GenesisToolBox
|
|||||||
|
|
||||||
SetBusy(true, "GetPcbId");
|
SetBusy(true, "GetPcbId");
|
||||||
|
|
||||||
// as new meter object will be generated the data grid shows outdated data
|
|
||||||
_dataTable.Rows.Clear();
|
_dataTable.Rows.Clear();
|
||||||
DisableAllButtons();
|
DisableAllButtons();
|
||||||
|
|
||||||
_currentPcbId = await Task.Run(() => interfaceToLaatzen.GetPcbId(slotNr));
|
GciPublicModels.GciGetPcbIdResult result =
|
||||||
|
await interfaceToLaatzen.GetPcbIdAsync(slotNr);
|
||||||
|
|
||||||
|
if (!result.Success)
|
||||||
|
throw new Exception(result.Message);
|
||||||
|
|
||||||
|
_currentPcbId = result.PcbId;
|
||||||
|
|
||||||
btnConnect.Enabled = true;
|
btnConnect.Enabled = true;
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -82,7 +82,7 @@
|
|||||||
this.lblConfigSource.Name = "lblConfigSource";
|
this.lblConfigSource.Name = "lblConfigSource";
|
||||||
this.lblConfigSource.Size = new System.Drawing.Size(75, 13);
|
this.lblConfigSource.Size = new System.Drawing.Size(75, 13);
|
||||||
this.lblConfigSource.TabIndex = 2;
|
this.lblConfigSource.TabIndex = 2;
|
||||||
this.lblConfigSource.Text = "ConfigSource:";
|
this.lblConfigSource.Text = "GciConfigSource:";
|
||||||
//
|
//
|
||||||
// cmbConfigSource
|
// cmbConfigSource
|
||||||
//
|
//
|
||||||
|
|||||||
@@ -160,9 +160,15 @@ namespace GenesisCordonelInterface.UI.StaraTuraAPI_GenesisCordonelInterface
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates PortConfig from UI values.
|
/// Creates a public GCI port configuration object from UI input values.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private PortConfig? CreatePortConfig(string portName, string baudRateText)
|
/// <param name="portName">Name of the port (e.g. COM3).</param>
|
||||||
|
/// <param name="baudRateText">Baud rate entered in the UI.</param>
|
||||||
|
/// <returns>
|
||||||
|
/// Instance of <see cref="GciPublicModels.GciPortConfig"/> or null if port name is empty.
|
||||||
|
/// </returns>
|
||||||
|
/// <exception cref="Exception">Thrown when baud rate is invalid.</exception>
|
||||||
|
private GciPublicModels.GciPortConfig CreateGciPortConfig(string portName, string baudRateText)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrWhiteSpace(portName))
|
if (string.IsNullOrWhiteSpace(portName))
|
||||||
return null;
|
return null;
|
||||||
@@ -170,35 +176,37 @@ namespace GenesisCordonelInterface.UI.StaraTuraAPI_GenesisCordonelInterface
|
|||||||
if (!int.TryParse(baudRateText, out int baudRate))
|
if (!int.TryParse(baudRateText, out int baudRate))
|
||||||
throw new Exception($"Invalid baud rate for port {portName}.");
|
throw new Exception($"Invalid baud rate for port {portName}.");
|
||||||
|
|
||||||
var cfg = new PortConfig
|
return new GciPublicModels.GciPortConfig
|
||||||
{
|
{
|
||||||
PortName = portName,
|
PortName = portName,
|
||||||
Type = "Serial"
|
Type = "Serial",
|
||||||
};
|
};
|
||||||
|
|
||||||
var sp = cfg.GetSerialPort();
|
|
||||||
if (sp == null)
|
|
||||||
throw new Exception($"Serial port object was not created for {portName}.");
|
|
||||||
|
|
||||||
sp.BaudRate = baudRate;
|
|
||||||
|
|
||||||
return cfg;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private ConfigSource GetConfigSource()
|
/// <summary>
|
||||||
|
/// Gets selected configuration source from UI and maps it to public GCI model.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>Selected <see cref="GciPublicModels.GciConfigSource"/>.</returns>
|
||||||
|
/// <exception cref="Exception">Thrown when no value is selected.</exception>
|
||||||
|
private GciPublicModels.GciConfigSource GetConfigSource()
|
||||||
{
|
{
|
||||||
if (cmbConfigSource.SelectedItem == null)
|
if (cmbConfigSource.SelectedItem == null)
|
||||||
throw new Exception("ConfigSource is not selected.");
|
throw new Exception("Config source is not selected.");
|
||||||
|
|
||||||
return (ConfigSource)cmbConfigSource.SelectedItem;
|
return (GciPublicModels.GciConfigSource)cmbConfigSource.SelectedItem;
|
||||||
}
|
}
|
||||||
|
|
||||||
private PasswordSource GetPasswordSource()
|
/// <summary>
|
||||||
|
/// Gets selected password source from UI and maps it to public GCI model.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>Selected <see cref="GciPublicModels.GciPasswordSource"/>.</returns>
|
||||||
|
/// <exception cref="Exception">Thrown when no value is selected.</exception>
|
||||||
|
private GciPublicModels.GciPasswordSource GetPasswordSource()
|
||||||
{
|
{
|
||||||
if (cmbPasswordSource.SelectedItem == null)
|
if (cmbPasswordSource.SelectedItem == null)
|
||||||
throw new Exception("PasswordSource is not selected.");
|
throw new Exception("Password source is not selected.");
|
||||||
|
|
||||||
return (PasswordSource)cmbPasswordSource.SelectedItem;
|
return (GciPublicModels.GciPasswordSource)cmbPasswordSource.SelectedItem;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
@@ -221,15 +229,19 @@ namespace GenesisCordonelInterface.UI.StaraTuraAPI_GenesisCordonelInterface
|
|||||||
|
|
||||||
await ExecuteApiActionAsync(async () =>
|
await ExecuteApiActionAsync(async () =>
|
||||||
{
|
{
|
||||||
var result = await _api.InitOneMeterFromExternAsync(
|
var request = new GciPublicModels.GciInitSlotRequest
|
||||||
slot,
|
{
|
||||||
GetConfigSource(),
|
SlotId = slot,
|
||||||
GetPasswordSource(),
|
ConfigSource = GetConfigSource(),
|
||||||
CreatePortConfig(txtRequestPort.Text, txtRequestBaudRate.Text),
|
PasswordSource = GetPasswordSource(),
|
||||||
CreatePortConfig(txtStreamingPort.Text, txtStreamingBaudRate.Text));
|
RequestPort = CreateGciPortConfig(txtRequestPort.Text, txtRequestBaudRate.Text),
|
||||||
|
StreamingPort = CreateGciPortConfig(txtStreamingPort.Text, txtStreamingBaudRate.Text)
|
||||||
|
};
|
||||||
|
|
||||||
|
var result = await _api.InitSlotAsync(request);
|
||||||
|
|
||||||
if (!result.Success)
|
if (!result.Success)
|
||||||
throw new Exception(result.ErrorMessage);
|
throw new Exception(result.Message);
|
||||||
|
|
||||||
MessageBox.Show("Meter initialized.");
|
MessageBox.Show("Meter initialized.");
|
||||||
});
|
});
|
||||||
@@ -251,10 +263,10 @@ namespace GenesisCordonelInterface.UI.StaraTuraAPI_GenesisCordonelInterface
|
|||||||
|
|
||||||
await ExecuteApiActionAsync(async () =>
|
await ExecuteApiActionAsync(async () =>
|
||||||
{
|
{
|
||||||
var result = await _api.ConnectOneMeterAsync(slot);
|
var result = await _api.ConnectOneSlotAsync(slot);
|
||||||
|
|
||||||
if (!result.Success)
|
if (!result.Success)
|
||||||
throw new Exception(result.ErrorMessage);
|
throw new Exception(result.Message);
|
||||||
|
|
||||||
MessageBox.Show($"Connected.\r\nPCB ID: {result.PcbId}");
|
MessageBox.Show($"Connected.\r\nPCB ID: {result.PcbId}");
|
||||||
});
|
});
|
||||||
@@ -280,7 +292,6 @@ namespace GenesisCordonelInterface.UI.StaraTuraAPI_GenesisCordonelInterface
|
|||||||
MessageBox.Show("Disconnected.");
|
MessageBox.Show("Disconnected.");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Reads PCB ID asynchronously.
|
/// Reads PCB ID asynchronously.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -297,8 +308,13 @@ namespace GenesisCordonelInterface.UI.StaraTuraAPI_GenesisCordonelInterface
|
|||||||
|
|
||||||
await ExecuteApiActionAsync(async () =>
|
await ExecuteApiActionAsync(async () =>
|
||||||
{
|
{
|
||||||
string pcbId = await _api.GetPcbIdAsync(slot);
|
GciPublicModels.GciGetPcbIdResult result =
|
||||||
MessageBox.Show($"PCB ID: {pcbId}");
|
await _api.GetPcbIdAsync(slot);
|
||||||
|
|
||||||
|
if (!result.Success)
|
||||||
|
throw new Exception(result.Message);
|
||||||
|
|
||||||
|
MessageBox.Show($"PCB ID: {result.PcbId}");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -345,10 +361,10 @@ namespace GenesisCordonelInterface.UI.StaraTuraAPI_GenesisCordonelInterface
|
|||||||
|
|
||||||
foreach (int slot in slots)
|
foreach (int slot in slots)
|
||||||
{
|
{
|
||||||
var result = await _api.ConnectOneMeterAsync(slot);
|
var result = await _api.ConnectOneSlotAsync(slot);
|
||||||
|
|
||||||
if (!result.Success)
|
if (!result.Success)
|
||||||
throw new Exception($"Slot {slot}: {result.ErrorMessage}");
|
throw new Exception($"Slot {slot}: {result.Message}");
|
||||||
}
|
}
|
||||||
|
|
||||||
MessageBox.Show("Selected meters connected.");
|
MessageBox.Show("Selected meters connected.");
|
||||||
|
|||||||
+2
-2
@@ -66,10 +66,10 @@ namespace GenesisCordonelInterface.UI.StaraTuraAPI_GenesisCordonelInterface
|
|||||||
|
|
||||||
foreach (int slot in _api.GetSelectedSlots())
|
foreach (int slot in _api.GetSelectedSlots())
|
||||||
{
|
{
|
||||||
var result = await _api.ConnectOneMeterAsync(slot);
|
var result = await _api.ConnectOneSlotAsync(slot);
|
||||||
|
|
||||||
if (!result.Success)
|
if (!result.Success)
|
||||||
throw new Exception($"Slot {slot}: {result.ErrorMessage}");
|
throw new Exception($"Slot {slot}: {result.Message}");
|
||||||
}
|
}
|
||||||
|
|
||||||
MessageBox.Show("Selected meters connected.");
|
MessageBox.Show("Selected meters connected.");
|
||||||
|
|||||||
@@ -0,0 +1,35 @@
|
|||||||
|
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Copies the prepared GCI runtime package into the TBF output directory.
|
||||||
|
This ensures all GCI dependencies are available next to TBF.exe.
|
||||||
|
-->
|
||||||
|
<Target Name="CopyGciRuntimePackageToTbfOutput" AfterTargets="Build">
|
||||||
|
|
||||||
|
<!-- Source directory containing the prepared GCI runtime package -->
|
||||||
|
<PropertyGroup>
|
||||||
|
<GciRuntimePackageDir>$(ProjectDir)..\GenesisCordonelInterface\RuntimePackage\Package\</GciRuntimePackageDir>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<!-- Collect runtime package files -->
|
||||||
|
<ItemGroup>
|
||||||
|
<GciRuntimeFiles Include="$(GciRuntimePackageDir)*.dll" />
|
||||||
|
<GciRuntimeFiles Include="$(GciRuntimePackageDir)*.exe" />
|
||||||
|
<GciRuntimeFiles Include="$(GciRuntimePackageDir)*.config" />
|
||||||
|
<GciRuntimeFiles Include="$(GciRuntimePackageDir)*.json" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<!-- Build output messages -->
|
||||||
|
<Message Text="Copying GCI runtime package to TBF output: $(TargetDir)" Importance="High" />
|
||||||
|
<Message Text="Source: $(GciRuntimePackageDir)" Importance="High" />
|
||||||
|
<Message Text="Files: @(GciRuntimeFiles)" Importance="Normal" />
|
||||||
|
|
||||||
|
<!-- Copy package files into TBF output directory -->
|
||||||
|
<Copy
|
||||||
|
SourceFiles="@(GciRuntimeFiles)"
|
||||||
|
DestinationFolder="$(TargetDir)"
|
||||||
|
SkipUnchangedFiles="false" />
|
||||||
|
|
||||||
|
</Target>
|
||||||
|
|
||||||
|
</Project>
|
||||||
@@ -1,13 +1,16 @@
|
|||||||
using log4net;
|
using GenesisCordonelInterface.API;
|
||||||
|
using log4net;
|
||||||
///
|
///
|
||||||
/// Copyright (c) 2015-2021 Sensus Slovensko a.s.
|
/// Copyright (c) 2015-2021 Sensus Slovensko a.s.
|
||||||
///
|
///
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
using TBF.Rig.Generic;
|
using TBF.Rig.Generic;
|
||||||
using ExternalInterfaceGUIType = GenesisCordonelInterface.UI.MainView;
|
using GciGUIType = GenesisCordonelInterface.UI.MainView;
|
||||||
using ExternalInterfaceType = GenesisCordonelInterface.API.InterfaceOutsideToGCI;
|
using GciType = GenesisCordonelInterface.API.InterfaceOutsideToGCI;
|
||||||
using UdsReaderType = TBF.Rig.Input.DataStorage.UniDataStorageReader.Reader;
|
using UdsReaderType = TBF.Rig.Input.DataStorage.UniDataStorageReader.Reader;
|
||||||
using UdsWriterType = TBF.Rig.Output.DataStorage.UniDataStorageWriter.Writer;
|
using UdsWriterType = TBF.Rig.Output.DataStorage.UniDataStorageWriter.Writer;
|
||||||
|
|
||||||
@@ -20,42 +23,37 @@ namespace TBF.Rig.BridgeComponents.GciBridge
|
|||||||
public class GciBridge : ComponentBase
|
public class GciBridge : ComponentBase
|
||||||
{
|
{
|
||||||
private static readonly ILog log = LogManager.GetLogger(typeof(GciBridge));
|
private static readonly ILog log = LogManager.GetLogger(typeof(GciBridge));
|
||||||
public override string ToString() { return string.Format("{0}({1})", ClassName, Cfg.ToString(-1)); }
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return string.Format("{0}({1})", ClassName, Cfg.ToString(-1));
|
||||||
|
}
|
||||||
|
|
||||||
readonly GciBridgeCfg gciBridgeCfg;
|
readonly GciBridgeCfg gciBridgeCfg;
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Linked UniDataStorage reader component.
|
|
||||||
/// </summary>
|
|
||||||
readonly UdsReaderType reader;
|
readonly UdsReaderType reader;
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Linked UniDataStorage writer component.
|
|
||||||
/// </summary>
|
|
||||||
readonly UdsWriterType writer;
|
readonly UdsWriterType writer;
|
||||||
|
|
||||||
/// <summary>
|
GciGUIType gciGUI;
|
||||||
/// Placeholder for GCI GUI entry point.
|
|
||||||
/// Replace object with real GCI MainForm type later.
|
|
||||||
/// </summary>
|
|
||||||
ExternalInterfaceGUIType gciGUI;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
///
|
|
||||||
/// </summary>
|
|
||||||
Form gciGuiHostForm;
|
Form gciGuiHostForm;
|
||||||
|
|
||||||
/// <summary>
|
GciType gciExternalInterface;
|
||||||
/// Placeholder for GCI external/public interface.
|
|
||||||
/// Replace object with real GCI interface type later.
|
|
||||||
/// </summary>
|
|
||||||
ExternalInterfaceType gciExternalInterface;
|
|
||||||
|
|
||||||
public bool HasReader { get { return reader != null; } }
|
public bool HasReader { get { return reader != null; } }
|
||||||
public bool HasWriter { get { return writer != null; } }
|
public bool HasWriter { get { return writer != null; } }
|
||||||
public bool IsGuiInitialized { get { return gciGUI != null; } }
|
public bool IsGuiInitialized { get { return gciGUI != null; } }
|
||||||
public bool IsExternalInitialized { get { return gciExternalInterface != null; } }
|
public bool IsExternalInitialized { get { return gciExternalInterface != null; } }
|
||||||
|
|
||||||
|
public UdsReaderType GetReader()
|
||||||
|
{
|
||||||
|
return reader;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UdsWriterType GetWriter()
|
||||||
|
{
|
||||||
|
return writer;
|
||||||
|
}
|
||||||
|
|
||||||
public GciBridge() { }
|
public GciBridge() { }
|
||||||
|
|
||||||
public GciBridge(IComponentCfg cfg, IList<IComponent> components)
|
public GciBridge(IComponentCfg cfg, IList<IComponent> components)
|
||||||
@@ -97,10 +95,6 @@ namespace TBF.Rig.BridgeComponents.GciBridge
|
|||||||
log.FatalFormat("{0} initialized: {1}", Name, this);
|
log.FatalFormat("{0} initialized: {1}", Name, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes access to GCI GUI.
|
|
||||||
/// Replace placeholder implementation with real MainForm creation.
|
|
||||||
/// </summary>
|
|
||||||
void TryInitializeGui()
|
void TryInitializeGui()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@@ -108,7 +102,7 @@ namespace TBF.Rig.BridgeComponents.GciBridge
|
|||||||
if (gciGuiHostForm != null && !gciGuiHostForm.IsDisposed)
|
if (gciGuiHostForm != null && !gciGuiHostForm.IsDisposed)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
gciGUI = new ExternalInterfaceGUIType();
|
gciGUI = new GciGUIType();
|
||||||
gciGUI.Dock = DockStyle.Fill;
|
gciGUI.Dock = DockStyle.Fill;
|
||||||
|
|
||||||
gciGuiHostForm = new Form();
|
gciGuiHostForm = new Form();
|
||||||
@@ -127,15 +121,14 @@ namespace TBF.Rig.BridgeComponents.GciBridge
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes access to GCI external/public interface.
|
|
||||||
/// Replace placeholder implementation with real interface creation.
|
|
||||||
/// </summary>
|
|
||||||
void TryInitializeExternalInterface()
|
void TryInitializeExternalInterface()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
gciExternalInterface = new ExternalInterfaceType();
|
if (gciExternalInterface != null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
gciExternalInterface = new GciType();
|
||||||
|
|
||||||
log.InfoFormat("{0}: GCI external interface initialized.", Name);
|
log.InfoFormat("{0}: GCI external interface initialized.", Name);
|
||||||
}
|
}
|
||||||
@@ -145,9 +138,6 @@ namespace TBF.Rig.BridgeComponents.GciBridge
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Shows GCI GUI if GUI access is enabled.
|
|
||||||
/// </summary>
|
|
||||||
public void ShowGui()
|
public void ShowGui()
|
||||||
{
|
{
|
||||||
if (!gciBridgeCfg.EnableGuiAccess) return;
|
if (!gciBridgeCfg.EnableGuiAccess) return;
|
||||||
@@ -165,9 +155,6 @@ namespace TBF.Rig.BridgeComponents.GciBridge
|
|||||||
log.InfoFormat("{0}: ShowGui invoked.", Name);
|
log.InfoFormat("{0}: ShowGui invoked.", Name);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Hides GCI GUI if GUI access is enabled.
|
|
||||||
/// </summary>
|
|
||||||
public void HideGui()
|
public void HideGui()
|
||||||
{
|
{
|
||||||
if (!gciBridgeCfg.EnableGuiAccess) return;
|
if (!gciBridgeCfg.EnableGuiAccess) return;
|
||||||
@@ -178,50 +165,120 @@ namespace TBF.Rig.BridgeComponents.GciBridge
|
|||||||
log.InfoFormat("{0}: HideGui invoked.", Name);
|
log.InfoFormat("{0}: HideGui invoked.", Name);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
void EnsureExternalInterface()
|
||||||
/// Connects the external GCI interface.
|
|
||||||
/// </summary>
|
|
||||||
public void ConnectExternal()
|
|
||||||
{
|
{
|
||||||
if (!gciBridgeCfg.EnableExternalAccess) return;
|
if (!gciBridgeCfg.EnableExternalAccess)
|
||||||
|
throw new Exception("GCI external access is disabled.");
|
||||||
|
|
||||||
if (!IsExternalInitialized)
|
if (!IsExternalInitialized)
|
||||||
{
|
|
||||||
TryInitializeExternalInterface();
|
TryInitializeExternalInterface();
|
||||||
}
|
|
||||||
|
|
||||||
/// TODO:
|
if (gciExternalInterface == null)
|
||||||
/// Replace with real external interface connect call.
|
throw new Exception("GCI external interface is not initialized.");
|
||||||
log.InfoFormat("{0}: ConnectExternal invoked.", Name);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
void EnsureReader()
|
||||||
/// Disconnects the external GCI interface.
|
|
||||||
/// </summary>
|
|
||||||
public void DisconnectExternal()
|
|
||||||
{
|
{
|
||||||
if (!gciBridgeCfg.EnableExternalAccess) return;
|
if (reader == null)
|
||||||
if (!IsExternalInitialized) return;
|
throw new Exception("UniDataStorageReader is not linked to GciBridge.");
|
||||||
|
|
||||||
/// TODO:
|
|
||||||
/// Replace with real external interface disconnect call.
|
|
||||||
log.InfoFormat("{0}: DisconnectExternal invoked.", Name);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
// API:
|
||||||
/// Returns linked reader component.
|
#region ======================================= GCI Public Interface =======================================
|
||||||
/// </summary>
|
|
||||||
public UdsReaderType GetReader()
|
public async Task<GciPublicModels.GciInitSlotResult> InitSlotAsync(GciPublicModels.GciInitSlotRequest request)
|
||||||
{
|
{
|
||||||
return reader;
|
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>
|
public async Task<GciPublicModels.GciSlotInfo> GetSlotAsync(int slotId)
|
||||||
/// Returns linked writer component.
|
|
||||||
/// </summary>
|
|
||||||
public UdsWriterType GetWriter()
|
|
||||||
{
|
{
|
||||||
return writer;
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<GciPublicModels.GciCleanSlotsResult> CleanSlotsAsync()
|
||||||
|
{
|
||||||
|
EnsureExternalInterface();
|
||||||
|
|
||||||
|
GciPublicModels.GciCleanSlotsResult result =
|
||||||
|
await gciExternalInterface.CleanSlotsAsync();
|
||||||
|
|
||||||
|
log.InfoFormat("{0}: CleanSlotsAsync invoked.", Name);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 async Task<GciPublicModels.GciDisconnectResult> DisconnectAsync(
|
||||||
|
int slotId,
|
||||||
|
CancellationToken token = default)
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -182,7 +182,7 @@ namespace TBF.Rig.BridgeComponents.GciBridge
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
bridge.ConnectExternal();
|
//bridge.ConnectExternal();
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -0,0 +1,14 @@
|
|||||||
|
using log4net;
|
||||||
|
///
|
||||||
|
/// Copyright (c) 2015-2021 Sensus Slovensko a.s.
|
||||||
|
///
|
||||||
|
using System;
|
||||||
|
using TBF.Rig.Sequences;
|
||||||
|
|
||||||
|
namespace TBF.Rig.BridgeComponents.GciBridge
|
||||||
|
{
|
||||||
|
public class GciBridgeOp
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -173,6 +173,10 @@
|
|||||||
<Reference Include="Xylem.Common.CommonCore">
|
<Reference Include="Xylem.Common.CommonCore">
|
||||||
<HintPath>..\packages\Common\Xylem.Common.CommonCore.dll</HintPath>
|
<HintPath>..\packages\Common\Xylem.Common.CommonCore.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
|
<Reference Include="Xylem.Common.Hardware.Interfaces.Ports.PortCore, Version=2.8.18.15967, Culture=neutral, processorArchitecture=MSIL">
|
||||||
|
<SpecificVersion>False</SpecificVersion>
|
||||||
|
<HintPath>..\packages\Common\Xylem.Common.Hardware.Interfaces.Ports.PortCore.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
<Reference Include="Xylem.Common.Hardware.WaterMeter.Genesis.GenesisConfig">
|
<Reference Include="Xylem.Common.Hardware.WaterMeter.Genesis.GenesisConfig">
|
||||||
<HintPath>..\packages\Common\Xylem.Common.Hardware.WaterMeter.Genesis.GenesisConfig.dll</HintPath>
|
<HintPath>..\packages\Common\Xylem.Common.Hardware.WaterMeter.Genesis.GenesisConfig.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
@@ -211,6 +215,7 @@
|
|||||||
<Compile Include="Rig\BridgeComponents\GciBridge\GciBridgeCfgCtrl.Designer.cs">
|
<Compile Include="Rig\BridgeComponents\GciBridge\GciBridgeCfgCtrl.Designer.cs">
|
||||||
<DependentUpon>GciBridgeCfgCtrl.cs</DependentUpon>
|
<DependentUpon>GciBridgeCfgCtrl.cs</DependentUpon>
|
||||||
</Compile>
|
</Compile>
|
||||||
|
<Compile Include="Rig\BridgeComponents\GciBridge\GciBridgeOp.cs" />
|
||||||
<Compile Include="Rig\BuiltIn\PumpTandem\Pump.cs" />
|
<Compile Include="Rig\BuiltIn\PumpTandem\Pump.cs" />
|
||||||
<Compile Include="Rig\BuiltIn\PumpTandem\PumpCfg.cs" />
|
<Compile Include="Rig\BuiltIn\PumpTandem\PumpCfg.cs" />
|
||||||
<Compile Include="Rig\BuiltIn\PumpTandem\PumpCfgCtrl.cs">
|
<Compile Include="Rig\BuiltIn\PumpTandem\PumpCfgCtrl.cs">
|
||||||
@@ -4168,6 +4173,7 @@
|
|||||||
<DependentUpon>TestProgressCtrl.cs</DependentUpon>
|
<DependentUpon>TestProgressCtrl.cs</DependentUpon>
|
||||||
</EmbeddedResource>
|
</EmbeddedResource>
|
||||||
<None Include="app.config" />
|
<None Include="app.config" />
|
||||||
|
<Content Include="Build\CopyGci.targets.xml" />
|
||||||
<Content Include="CameraBinaryFiles\GrabImage">
|
<Content Include="CameraBinaryFiles\GrabImage">
|
||||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
</Content>
|
</Content>
|
||||||
@@ -4385,6 +4391,7 @@
|
|||||||
<Name>Results</Name>
|
<Name>Results</Name>
|
||||||
</ProjectReference>
|
</ProjectReference>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
<Import Project="Build\CopyGci.targets.xml" />
|
||||||
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
|
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
|
||||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||||
Other similar extension points exist, see Microsoft.Common.targets.
|
Other similar extension points exist, see Microsoft.Common.targets.
|
||||||
|
|||||||
Reference in New Issue
Block a user