kick 2 - prva dobra s dialogom testov

This commit is contained in:
2026-09-11 00:33:16 +02:00
parent 45a6d59b5e
commit cf77faf972
12 changed files with 1128 additions and 493 deletions
@@ -0,0 +1,355 @@
using System;
using System.Collections.Generic;
using System.Collections.Concurrent;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Common;
using Config.Entities;
using TBF.Rig.Generic;
using GenesisCordonelInterface.Core.Threading;
using GciPublicModels = GenesisCordonelInterface.API.PublicModels;
namespace TBF.Rig.BridgeComponents.GciBridge
{
public partial class GciBridge
{
public bool IsSimulation { get { return DebugLevel == DebugMode.Simulate; } }
public GciSimulationSettings Simulation { get; } = new GciSimulationSettings();
private readonly AsyncLocal<GciSimulationProfile> simulationOverride = new AsyncLocal<GciSimulationProfile>();
// Scoped to this execution context, including awaited calls; does not change defaults.
public IDisposable BeginSimulation(GciSimulationProfile profile)
{
if (!IsSimulation) throw new InvalidOperationException("GCI Bridge must be in Simulate mode.");
if (profile == null) throw new ArgumentNullException("profile");
var previous = simulationOverride.Value;
simulationOverride.Value = profile.Snapshot();
return new SimulationScope(() => simulationOverride.Value = previous);
}
private sealed class SimulationScope : IDisposable
{
private Action restore;
public SimulationScope(Action restore) { this.restore = restore; }
public void Dispose() { var action = restore; restore = null; if (action != null) action(); }
}
private readonly object simulationLock = new object();
private readonly Dictionary<int, GciPublicModels.GciSlotInfo> simulationSlots = new Dictionary<int, GciPublicModels.GciSlotInfo>();
private readonly Dictionary<int, GciPublicModels.WorkerDebugStatus> simulationWorkers = new Dictionary<int, GciPublicModels.WorkerDebugStatus>();
private readonly ConcurrentDictionary<int, SemaphoreSlim> simulationGates = new ConcurrentDictionary<int, SemaphoreSlim>();
private readonly HashSet<int> simulationSelection = new HashSet<int>();
private static readonly NLog.Logger simulationLogger = NLog.LogManager.GetLogger("GenesisCordonelInterface.GciBridge.Simulation");
public event Action<int, string> SimulationLog;
private void LogSimulation(int slot, string operation, string message)
{
var entry = new NLog.LogEventInfo(NLog.LogLevel.Info, simulationLogger.Name, string.Format("[SIMULATION] Bridge={0}, Slot={1}, Operation={2}, {3}", Name, slot, operation, message));
entry.Properties["Slot"] = slot;
entry.Properties["Operation"] = operation;
entry.Properties["Bridge"] = Name;
simulationLogger.Log(entry);
var handlers = SimulationLog;
if (handlers == null) return;
int[] targets;
lock (simulationLock) targets = slot > 0 ? new[] { slot } : simulationSelection.ToArray();
foreach (int target in targets)
{
foreach (Action<int, string> handler in handlers.GetInvocationList())
{
try { handler(target, entry.Message); }
catch (Exception ex) { log.Warn("Simulation diagnostic subscriber failed.", ex); }
}
}
}
private async Task<T> SimulateAsync<T>(string operation, int slot, CancellationToken token, Func<GciSimulationProfile, T> create, string register = null)
{
token.ThrowIfCancellationRequested();
var profile = Simulation.Get(operation, register);
var dynamicProfile = simulationOverride.Value;
if (dynamicProfile != null)
{
profile.DurationMs = dynamicProfile.DurationMs;
profile.Success = dynamicProfile.Success;
profile.ErrorMessage = dynamicProfile.ErrorMessage;
}
var gate = simulationGates.GetOrAdd(slot, _ => new SemaphoreSlim(1, 1));
lock (simulationLock)
{
if (!simulationWorkers.ContainsKey(slot)) simulationWorkers[slot] = new GciPublicModels.WorkerDebugStatus { Slot = slot, Name = slot == 0 ? "Simulated batch" : "Simulated slot " + slot };
simulationWorkers[slot].QueueLength++;
}
bool acquired = false;
try
{
await gate.WaitAsync(token).ConfigureAwait(false);
acquired = true;
lock (simulationLock)
{
var worker = simulationWorkers[slot];
worker.QueueLength--;
worker.IsBusy = true;
worker.CurrentOperation = operation;
worker.LastError = null;
worker.LastActivity = DateTime.Now;
}
LogSimulation(slot, operation, "START, DurationMs=" + profile.DurationMs);
await Task.Delay(profile.DurationMs, token).ConfigureAwait(false);
token.ThrowIfCancellationRequested();
T result;
lock (simulationLock)
{
result = create(profile);
simulationWorkers[slot].LastError = profile.Success ? null : profile.ErrorMessage;
}
LogSimulation(slot, operation, "FINISH, Success=" + profile.Success + ", ErrorMessage=" + profile.ErrorMessage);
return result;
}
catch (OperationCanceledException)
{
LogSimulation(slot, operation, "CANCELLED");
throw;
}
finally
{
lock (simulationLock)
{
var worker = simulationWorkers[slot];
if (!acquired) worker.QueueLength--;
else
{
worker.IsBusy = false;
worker.CurrentOperation = null;
worker.LastActivity = DateTime.Now;
}
}
if (acquired) gate.Release();
}
}
private static void ValidateSimulationSlot(int slot)
{
if (slot <= 0) throw new ArgumentOutOfRangeException("slot");
}
private string SimulationPcb(int slot, GciSimulationProfile profile)
{
return profile.PcbId ?? (900000000L + slot).ToString(System.Globalization.CultureInfo.InvariantCulture);
}
// Successful canned operations may create a logical slot; no COM device is created.
private GciPublicModels.GciSlotInfo SimSlot(int slot, GciSimulationProfile profile)
{
GciPublicModels.GciSlotInfo state;
if (!simulationSlots.TryGetValue(slot, out state))
{
state = new GciPublicModels.GciSlotInfo { SlotId = slot, Exists = true, Success = true, PcbId = SimulationPcb(slot, profile) };
simulationSlots.Add(slot, state);
simulationSelection.Add(slot);
}
return state;
}
private static GciPublicModels.GciPortConfig CopyPort(GciPublicModels.GciPortConfig port)
{
return port == null ? null : new GciPublicModels.GciPortConfig { PortName = port.PortName, Type = port.Type };
}
private static GciPublicModels.GciSlotInfo CopySlot(GciPublicModels.GciSlotInfo s)
{
return new GciPublicModels.GciSlotInfo { SlotId = s.SlotId, Exists = s.Exists, Success = s.Success, IsConnected = s.IsConnected, IsLoggedOn = s.IsLoggedOn, Message = s.Message, PcbId = s.PcbId, Password = s.Password, ConfigSource = s.ConfigSource, PasswordSource = s.PasswordSource, RequestPort = CopyPort(s.RequestPort), StreamingPort = CopyPort(s.StreamingPort) };
}
private Task<GciPublicModels.GciInitSlotResult> SimInit(string operation, GciPublicModels.GciInitSlotRequest request, CancellationToken token)
{
if (request == null) throw new ArgumentNullException("request");
ValidateSimulationSlot(request.SlotId);
return SimulateAsync(operation, request.SlotId, token, p =>
{
bool existed = simulationSlots.ContainsKey(request.SlotId);
if (p.Success)
{
var s = SimSlot(request.SlotId, p);
s.RequestPort = CopyPort(request.RequestPort);
s.StreamingPort = CopyPort(request.StreamingPort);
s.Password = request.Password;
s.ConfigSource = request.ConfigSource;
s.PasswordSource = request.PasswordSource;
}
return new GciPublicModels.GciInitSlotResult { SlotId = request.SlotId, Success = p.Success, Message = p.ErrorMessage, PcbId = p.Success ? SimulationPcb(request.SlotId, p) : null, Created = p.Success && !existed, Updated = p.Success && existed, AlreadyExists = existed };
});
}
private Task<GciPublicModels.PreAdjustmentProcessResult> SimPhase(string operation, int slot, CancellationToken token)
{
return SimulateAsync(operation, slot, token, p => new GciPublicModels.PreAdjustmentProcessResult { Success = p.Success, Slot = slot, ProcessName = operation, ErrorMessage = p.ErrorMessage });
}
private int[] GetSimulatedPreadjustmentSlots()
{
lock (simulationLock)
{
// Slot 0 represented the old aggregate simulation. Preadjustment now reports
// only real logical slot workers.
GciPublicModels.WorkerDebugStatus batchWorker;
if (simulationWorkers.TryGetValue(0, out batchWorker) && !batchWorker.IsBusy) simulationWorkers.Remove(0);
return simulationSelection.OrderBy(slot => slot).ToArray();
}
}
private async Task<GciPublicModels.PreAdjustmentProcessResult> SimBatchPhase(string operation, CancellationToken token)
{
int[] slots = GetSimulatedPreadjustmentSlots();
if (slots.Length == 0)
return new GciPublicModels.PreAdjustmentProcessResult { Success = false, Slot = -1, ProcessName = operation, ErrorMessage = "No simulated preadjustment slots are selected." };
// Start every slot operation before awaiting the aggregate. SimulateAsync supplies
// an independent worker and serialization gate for each slot.
Task<GciPublicModels.PreAdjustmentProcessResult>[] tasks = slots.Select(slot => SimPhase(operation, slot, token)).ToArray();
GciPublicModels.PreAdjustmentProcessResult[] results = await Task.WhenAll(tasks).ConfigureAwait(false);
GciPublicModels.PreAdjustmentProcessResult[] failed = results.Where(result => !result.Success).ToArray();
return new GciPublicModels.PreAdjustmentProcessResult
{
Success = failed.Length == 0,
Slot = -1,
ProcessName = operation,
ErrorMessage = failed.Length == 0 ? null : string.Join("; ", failed.Select(result => "Slot " + result.Slot + ": " + result.ErrorMessage))
};
}
private async Task<GciPublicModels.PreAdjustmentProcessResult> SimInitializeBatch(string operation, IEnumerable<int> selectedSlots, CancellationToken token)
{
int[] slots = selectedSlots.Distinct().OrderBy(slot => slot).ToArray();
if (slots.Length == 0)
return new GciPublicModels.PreAdjustmentProcessResult { Success = false, Slot = -1, ProcessName = operation, ErrorMessage = "No simulated preadjustment slots were supplied." };
lock (simulationLock)
{
GciPublicModels.WorkerDebugStatus batchWorker;
if (simulationWorkers.TryGetValue(0, out batchWorker) && !batchWorker.IsBusy) simulationWorkers.Remove(0);
simulationSelection.Clear();
foreach (int slot in slots)
{
// Keep failed simulated slots visible in diagnostics until GenesisCommunication
// records and excludes them.
SimSlot(slot, Simulation.Get(operation, null));
simulationSelection.Add(slot);
}
}
Task<GciPublicModels.PreAdjustmentProcessResult>[] tasks = slots.Select(slot => SimPhase(operation, slot, token)).ToArray();
GciPublicModels.PreAdjustmentProcessResult[] results = await Task.WhenAll(tasks).ConfigureAwait(false);
GciPublicModels.PreAdjustmentProcessResult[] failed = results.Where(result => !result.Success).ToArray();
return new GciPublicModels.PreAdjustmentProcessResult
{
Success = failed.Length == 0,
Slot = -1,
ProcessName = operation,
ErrorMessage = failed.Length == 0 ? null : string.Join("; ", failed.Select(result => "Slot " + result.Slot + ": " + result.ErrorMessage))
};
}
// Aggregate simulation for UI-only workflows (Q3, preparation check, hold).
// This deliberately does not claim to execute their individual register steps.
public Task<GciPublicModels.PreAdjustmentProcessResult> SimulateMeterActivityAsync(string activity, int slot, CancellationToken token = default(CancellationToken))
{
if (!IsSimulation) throw new InvalidOperationException("GCI Bridge must be in Simulate mode.");
ValidateSimulationSlot(slot);
return SimulateAsync("MeterActivity", slot, token, p =>
{
if (p.Success) SimSlot(slot, p);
return new GciPublicModels.PreAdjustmentProcessResult { Success = p.Success, Slot = slot, ProcessName = activity, ErrorMessage = p.ErrorMessage };
});
}
private Task<Interfaces.PublicModels.GciFullLoginResult> SimFullLogin(int slot, CancellationToken token)
{
// One independently configurable canned workflow; does not also delay every child.
return SimulateAsync("ConnectFullPassLoginWithRetryAsync", slot, token, p =>
{
string pcb = p.Success ? SimulationPcb(slot, p) : null;
if (p.Success)
{
var s = SimSlot(slot, p);
s.IsConnected = true;
s.IsLoggedOn = true;
s.Password = p.Password;
}
return new Interfaces.PublicModels.GciFullLoginResult
{
SlotId = slot, Success = p.Success, Message = p.ErrorMessage,
ConnectResult = SimRetry(new GciPublicModels.GciConnectResult { SlotId = slot, Success = p.Success, IsConnected = p.Success, PcbId = pcb, Message = p.ErrorMessage }, p),
PcbResult = p.Success ? SimRetry(new GciPublicModels.GciGetPcbIdResult { SlotId = slot, Success = true, PcbId = pcb }, p) : null,
PasswordResult = p.Success ? SimRetry(new Interfaces.PublicModels.UdsPasswordResult { Success = true, PcbId = pcb, Password = p.Password }, p) : null,
SetPasswordResult = p.Success ? SimRetry(new GciPublicModels.GciSetPasswordResult { SlotId = slot, Success = true, Password = p.Password }, p) : null,
LoginResult = p.Success ? SimRetry(new GciPublicModels.GciLoginResult { SlotId = slot, Success = true, IsLoggedOn = true, PcbId = pcb }, p) : null
};
});
}
private static RetryResult<T> SimRetry<T>(T result, GciSimulationProfile p)
{
return new RetryResult<T> { Result = result, Success = p.Success, Attempts = 1, Duration = TimeSpan.Zero, TimedOut = false };
}
private async Task<GciPublicModels.PreadjustmentDetectResult> SimDetect(IEnumerable<GciPublicModels.MeterBatchDebugStatus> slots, CancellationToken token)
{
if (slots == null) throw new ArgumentNullException("slots");
int[] selected = slots.Where(status => status.Selected).Select(status => status.Slot).Distinct().OrderBy(slot => slot).ToArray();
foreach (int slot in selected) ValidateSimulationSlot(slot);
if (selected.Length == 0) return new GciPublicModels.PreadjustmentDetectResult { Success = false, ErrorMessage = "No simulated slots are selected.", DetectedMeterCount = 0 };
lock (simulationLock)
{
GciPublicModels.WorkerDebugStatus batchWorker;
if (simulationWorkers.TryGetValue(0, out batchWorker) && !batchWorker.IsBusy) simulationWorkers.Remove(0);
simulationSelection.Clear();
foreach (int slot in selected)
{
SimSlot(slot, Simulation.Get("PreAdjustment_Detect", null));
simulationSelection.Add(slot);
}
}
Task<GciPublicModels.PreAdjustmentProcessResult>[] tasks = selected.Select(slot => SimPhase("PreAdjustment_Detect", slot, token)).ToArray();
GciPublicModels.PreAdjustmentProcessResult[] results = await Task.WhenAll(tasks).ConfigureAwait(false);
GciPublicModels.PreAdjustmentProcessResult[] failed = results.Where(result => !result.Success).ToArray();
return new GciPublicModels.PreadjustmentDetectResult
{
Success = failed.Length == 0,
ErrorMessage = failed.Length == 0 ? null : string.Join("; ", failed.Select(result => "Slot " + result.Slot + ": " + result.ErrorMessage)),
DetectedMeterCount = results.Count(result => result.Success)
};
}
// Exclusion changes both the overview selection and the process control.
public void ExcludePreadjustmentSlot(int slot)
{
if (IsSimulation) { lock (simulationLock) simulationSelection.Remove(slot); return; }
EnsureExternalInterface();
gciExternalInterface.SetSlotSelected(slot, false);
var controls = gciExternalInterface._innerMeterAPI._meterControls;
if (controls == null) return;
foreach (var control in controls.Where(c => c.Slot == slot))
{
control.SetChecked(false);
control.IsEnabled = false;
}
}
public List<GciPublicModels.MeterBatchDebugStatus> GetMeterBatchDebugStatuses()
{
if (!IsSimulation) { EnsureExternalInterface(); return gciExternalInterface.GetMeterBatchDebugStatuses(); }
lock (simulationLock)
return simulationSlots.Values.OrderBy(s => s.SlotId).Select(s => new GciPublicModels.MeterBatchDebugStatus { Slot = s.SlotId, Selected = simulationSelection.Contains(s.SlotId), PcbId = s.PcbId, IsConnected = s.IsConnected, IsLoggedOn = s.IsLoggedOn, FwVersion = "SIM", RequestPort = s.RequestPort == null ? "" : s.RequestPort.PortName, RequestPortType = s.RequestPort == null ? "" : s.RequestPort.Type, StreamingPort = s.StreamingPort == null ? "" : s.StreamingPort.PortName }).ToList();
}
public List<GciPublicModels.WorkerDebugStatus> GetWorkerDebugStatuses()
{
if (!IsSimulation) { EnsureExternalInterface(); return gciExternalInterface.GetWorkerDebugStatuses(); }
lock (simulationLock)
return simulationWorkers.Values.OrderBy(s => s.Slot).Select(s => new GciPublicModels.WorkerDebugStatus { Slot = s.Slot, Name = s.Name, QueueLength = s.QueueLength, IsBusy = s.IsBusy, CurrentOperation = s.CurrentOperation, LastActivity = s.LastActivity, LastError = s.LastError }).ToList();
}
}
}
+160 -2
View File
@@ -11,6 +11,7 @@ using NHibernate.Mapping;
/// Copyright (c) 2015-2021 Sensus Slovensko a.s.
///
using System;
using System.Linq;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
@@ -41,7 +42,7 @@ namespace TBF.Rig.BridgeComponents.GciBridge
/// 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
public partial class GciBridge : ComponentBase
{
private static readonly ILog log = LogManager.GetLogger(typeof(GciBridge));
@@ -134,6 +135,7 @@ namespace TBF.Rig.BridgeComponents.GciBridge
public override void Initialize()
{
if (IsSimulation) { log.InfoFormat("{0}: Simulation mode initialized; hardware initialization skipped.", Name); return; }
if (gciBridgeCfg.EnableExternalAccess)
{
TryInitializeExternalInterface();
@@ -218,6 +220,7 @@ namespace TBF.Rig.BridgeComponents.GciBridge
public void ShowGciGui()
{
if (IsSimulation) { MessageBox.Show("Use GenesisCommunication diagnostics for simulated slots. The hardware GCI GUI is unavailable in Simulate mode.", "GCI simulation"); return; }
if (!gciBridgeCfg.EnableGuiAccess) return;
if (gciGuiHostForm == null || gciGuiHostForm.IsDisposed)
@@ -245,6 +248,7 @@ namespace TBF.Rig.BridgeComponents.GciBridge
public void ShowGui()
{
if (IsSimulation) { MessageBox.Show("Use GenesisCommunication diagnostics for simulated slots. The hardware GCI GUI is unavailable in Simulate mode.", "GCI simulation"); return; }
if (!gciBridgeCfg.EnableGuiAccess) return;
if (gciBridgeGuiForm == null || gciBridgeGuiForm.IsDisposed)
@@ -310,6 +314,10 @@ namespace TBF.Rig.BridgeComponents.GciBridge
GciPublicModels.GciInitSlotRequest request,
CancellationToken token = default)
{
if (IsSimulation)
{
return await SimInit(nameof(InitSlotAsync), request, token).ConfigureAwait(false);
}
EnsureExternalInterface();
if (request == null)
@@ -391,6 +399,10 @@ namespace TBF.Rig.BridgeComponents.GciBridge
GciPublicModels.GciInitSlotRequest request,
CancellationToken token = default)
{
if (IsSimulation)
{
return await SimInit(nameof(UpdateSlotAsync), request, token).ConfigureAwait(false);
}
EnsureExternalInterface();
if (request == null)
@@ -469,6 +481,12 @@ namespace TBF.Rig.BridgeComponents.GciBridge
int slotId,
CancellationToken token = default)
{
if (IsSimulation)
{
ValidateSimulationSlot(slotId);
return await SimulateAsync(nameof(GetSlotAsync), slotId, token, p => { if (!p.Success) return new GciPublicModels.GciSlotInfo { SlotId = slotId, Success = false, Message = p.ErrorMessage }; var copy = CopySlot(SimSlot(slotId, p)); copy.Message = p.ErrorMessage; return copy; }).ConfigureAwait(false);
}
EnsureExternalInterface();
if (slotId <= 0)
@@ -545,6 +563,12 @@ namespace TBF.Rig.BridgeComponents.GciBridge
int slot,
CancellationToken token = default)
{
if (IsSimulation)
{
ValidateSimulationSlot(slot);
return await SimulateAsync(nameof(CleanSlotAsync), slot, token, p => { if (p.Success) { simulationSlots.Remove(slot); simulationSelection.Remove(slot); } return new GciPublicModels.GciCleanSlotResult { SlotId = slot, Success = p.Success, Message = p.ErrorMessage }; }).ConfigureAwait(false);
}
EnsureExternalInterface();
if (slot <= 0)
@@ -621,6 +645,12 @@ namespace TBF.Rig.BridgeComponents.GciBridge
public async Task<GciPublicModels.GciCleanAllSlotsResult> CleanAllSlotsAsync(
CancellationToken token = default)
{
if (IsSimulation)
{
return await SimulateAsync(nameof(CleanAllSlotsAsync), 0, token, p => { if (p.Success) { simulationSlots.Clear(); simulationSelection.Clear(); } return new GciPublicModels.GciCleanAllSlotsResult { Success = p.Success, Message = p.ErrorMessage }; }).ConfigureAwait(false);
}
EnsureExternalInterface();
GciPublicModels.GciCleanAllSlotsResult result =
@@ -693,6 +723,12 @@ namespace TBF.Rig.BridgeComponents.GciBridge
int slotId,
CancellationToken token = default)
{
if (IsSimulation)
{
ValidateSimulationSlot(slotId);
return await SimulateAsync(nameof(GetPcbIdAsync), slotId, token, p => { if (p.Success) SimSlot(slotId, p).PcbId = SimulationPcb(slotId, p); return new GciPublicModels.GciGetPcbIdResult { SlotId = slotId, Success = p.Success, PcbId = p.Success ? SimulationPcb(slotId, p) : null, Message = p.ErrorMessage }; }).ConfigureAwait(false);
}
EnsureExternalInterface();
if (slotId <= 0)
@@ -810,6 +846,12 @@ namespace TBF.Rig.BridgeComponents.GciBridge
int slot,
CancellationToken token = default)
{
if (IsSimulation)
{
ValidateSimulationSlot(slot);
return await SimulateAsync(nameof(ConnectAsync), slot, token, p => { if (p.Success) SimSlot(slot, p).IsConnected = true; return new GciPublicModels.GciConnectResult { SlotId = slot, Success = p.Success, IsConnected = p.Success, PcbId = p.Success ? SimulationPcb(slot, p) : null, Message = p.ErrorMessage }; }).ConfigureAwait(false);
}
EnsureExternalInterface();
if (slot <= 0)
@@ -842,6 +884,12 @@ namespace TBF.Rig.BridgeComponents.GciBridge
int slotId,
CancellationToken token = default)
{
if (IsSimulation)
{
ValidateSimulationSlot(slotId);
return await SimulateAsync(nameof(LoginAsync), slotId, token, p => { if (p.Success) { SimSlot(slotId, p).IsConnected = true; SimSlot(slotId, p).IsLoggedOn = true; } return new GciPublicModels.GciLoginResult { SlotId = slotId, Success = p.Success, IsLoggedOn = p.Success, PcbId = p.Success ? SimulationPcb(slotId, p) : null, Message = p.ErrorMessage }; }).ConfigureAwait(false);
}
EnsureExternalInterface();
if (slotId <= 0)
@@ -913,6 +961,12 @@ namespace TBF.Rig.BridgeComponents.GciBridge
int slotId,
CancellationToken token = default)
{
if (IsSimulation)
{
ValidateSimulationSlot(slotId);
return await SimulateAsync(nameof(DisconnectAsync), slotId, token, p => { if (p.Success && simulationSlots.ContainsKey(slotId)) { simulationSlots[slotId].IsConnected = false; simulationSlots[slotId].IsLoggedOn = false; } return new GciPublicModels.GciDisconnectResult { SlotId = slotId, Success = p.Success, Message = p.ErrorMessage }; }).ConfigureAwait(false);
}
EnsureExternalInterface();
if (slotId <= 0)
@@ -992,6 +1046,12 @@ namespace TBF.Rig.BridgeComponents.GciBridge
string password,
CancellationToken token = default)
{
if (IsSimulation)
{
ValidateSimulationSlot(slotId);
if (string.IsNullOrWhiteSpace(password)) throw new ArgumentException("Password is empty.");
return await SimulateAsync(nameof(SetPasswordAsync), slotId, token, p => { if (p.Success) SimSlot(slotId, p).Password = password; return new GciPublicModels.GciSetPasswordResult { SlotId = slotId, Success = p.Success, Password = p.Success ? password : null, Message = p.ErrorMessage }; }).ConfigureAwait(false);
}
EnsureExternalInterface();
if (slotId <= 0)
@@ -1068,6 +1128,12 @@ namespace TBF.Rig.BridgeComponents.GciBridge
string registerName,
CancellationToken token = default)
{
if (IsSimulation)
{
ValidateSimulationSlot(slotId);
if (string.IsNullOrWhiteSpace(registerName)) throw new ArgumentException("Register name is empty.");
return await SimulateAsync(nameof(ReadRegisterAsync), slotId, token, p => new GciPublicModels.RegisterReadResult { Success = p.Success, RegisterName = registerName, RawHex = p.Success ? p.RawHex : null, ErrorMessage = p.ErrorMessage }, registerName).ConfigureAwait(false);
}
EnsureExternalInterface();
if (slotId <= 0)
@@ -1158,6 +1224,12 @@ namespace TBF.Rig.BridgeComponents.GciBridge
bool refreshSystemState = false,
CancellationToken token = default)
{
if (IsSimulation)
{
ValidateSimulationSlot(slotId);
if (string.IsNullOrWhiteSpace(registerName)) throw new ArgumentException("Register name is empty.");
return await SimulateAsync(nameof(WriteRegisterAsync), slotId, token, p => new GciPublicModels.RegisterWriteResult { Success = p.Success, RegisterName = registerName, WrittenValue = value, StoreToDevice = storeToDevice, RefreshSystemState = refreshSystemState, ErrorMessage = p.ErrorMessage }, registerName).ConfigureAwait(false);
}
EnsureExternalInterface();
if (slotId <= 0)
@@ -1261,6 +1333,12 @@ namespace TBF.Rig.BridgeComponents.GciBridge
string pcbId,
CancellationToken token = default)
{
if (IsSimulation)
{
if (string.IsNullOrWhiteSpace(pcbId)) throw new ArgumentException("PCB ID is empty.");
return await SimulateAsync(nameof(GetPasswordAsync), 0, token, p => { return new UdsPasswordResult { Success = p.Success, PcbId = pcbId, Password = p.Success ? p.Password : null, Message = p.ErrorMessage }; }).ConfigureAwait(false);
}
EnsureReader();
if (string.IsNullOrWhiteSpace(pcbId))
@@ -1339,6 +1417,12 @@ namespace TBF.Rig.BridgeComponents.GciBridge
int meterSize,
CancellationToken token = default)
{
if (IsSimulation)
{
if (meterSize < 0) throw new ArgumentOutOfRangeException("meterSize");
return await SimulateAsync(nameof(GetPreAdjustmentCalibrationParamsAsync), 0, token, p => { return new UdsPreAdjustmentCalibrationParamsResult { Success = p.Success, MeterSize = meterSize, CalibrationParams = p.Success ? new Dictionary<string, UInt32>(p.CalibrationParams) : null, Message = p.ErrorMessage }; }).ConfigureAwait(false);
}
EnsureReader();
if (meterSize < 0)
@@ -1526,6 +1610,11 @@ namespace TBF.Rig.BridgeComponents.GciBridge
/// <returns>Complete workflow result including all retry statistics and operation results.</returns>
public async Task<GciFullLoginResult> ConnectFullPassLoginWithRetryAsync(int slotId, CancellationToken token = default)
{
if (IsSimulation)
{
ValidateSimulationSlot(slotId);
return await SimFullLogin(slotId, token).ConfigureAwait(false);
}
EnsureExternalInterface();
EnsureReader();
@@ -1581,6 +1670,14 @@ namespace TBF.Rig.BridgeComponents.GciBridge
public PreAdjustmentInitializationResult Preadjustment_Initialization(
ProcessProgress pp, List<MeterStateControl> mc)
{
if (IsSimulation)
{
if (pp == null || mc == null) throw new ArgumentNullException(pp == null ? "pp" : "mc");
var slots = mc.Where(m => m.IsEnabled).Select(m => m.Slot).Distinct().ToArray();
foreach (int slot in slots) ValidateSimulationSlot(slot);
GciPublicModels.PreAdjustmentProcessResult simulated = SimInitializeBatch(nameof(Preadjustment_Initialization), slots, CancellationToken.None).GetAwaiter().GetResult();
return new PreAdjustmentInitializationResult { Success = simulated.Success, ErrorMessage = simulated.ErrorMessage, Slots = simulated.Success ? string.Join(",", slots) : "" };
}
const string operation = nameof(Preadjustment_Initialization);
try
@@ -1627,6 +1724,10 @@ namespace TBF.Rig.BridgeComponents.GciBridge
IEnumerable<GciPublicModels.MeterBatchDebugStatus> selectedSlots,
CancellationToken token = default)
{
if (IsSimulation)
{
return await SimDetect(selectedSlots, token).ConfigureAwait(false);
}
const string operation = nameof(PreAdjustment_DetectAsync);
try
@@ -1666,6 +1767,10 @@ namespace TBF.Rig.BridgeComponents.GciBridge
IEnumerable<GciPublicModels.MeterBatchDebugStatus> selectedSlots,
CancellationToken token = default)
{
if (IsSimulation)
{
return SimDetect(selectedSlots, token).GetAwaiter().GetResult();
}
const string operation = nameof(PreAdjustment_DetectDirect);
try
@@ -1700,6 +1805,11 @@ namespace TBF.Rig.BridgeComponents.GciBridge
int slot,
CancellationToken token = default)
{
if (IsSimulation)
{
ValidateSimulationSlot(slot);
return await SimPhase("PreAdjustment_Preparation", slot, token).ConfigureAwait(false);
}
const string operation = nameof(PreAdjustment_PreparationAsync);
try
@@ -1745,6 +1855,10 @@ namespace TBF.Rig.BridgeComponents.GciBridge
public PreAdjustmentProcessResult PreAdjustment_PreparationDirect()
{
if (IsSimulation)
{
return SimBatchPhase("PreAdjustment_Preparation", CancellationToken.None).GetAwaiter().GetResult();
}
const string operation = nameof(PreAdjustment_PreparationDirect);
try
@@ -1780,6 +1894,11 @@ namespace TBF.Rig.BridgeComponents.GciBridge
int slot,
CancellationToken token = default)
{
if (IsSimulation)
{
ValidateSimulationSlot(slot);
return await SimPhase("PreAdjustment_AmplitudeTest", slot, token).ConfigureAwait(false);
}
const string operation = nameof(PreAdjustment_AmplitudeTestAsync);
try
@@ -1825,6 +1944,10 @@ namespace TBF.Rig.BridgeComponents.GciBridge
public PreAdjustmentProcessResult PreAdjustment_AmplitudeTestDirect()
{
if (IsSimulation)
{
return SimBatchPhase("PreAdjustment_AmplitudeTest", CancellationToken.None).GetAwaiter().GetResult();
}
const string operation = nameof(PreAdjustment_AmplitudeTestDirect);
try
@@ -1860,6 +1983,11 @@ namespace TBF.Rig.BridgeComponents.GciBridge
int slot,
CancellationToken token = default)
{
if (IsSimulation)
{
ValidateSimulationSlot(slot);
return await SimPhase("PreAdjustment_TemperatureCalibration", slot, token).ConfigureAwait(false);
}
const string operation = nameof(PreAdjustment_TemperatureCalibrationAsync);
try
@@ -1906,6 +2034,10 @@ namespace TBF.Rig.BridgeComponents.GciBridge
public bool PreAdjustment_PushTemperature(
double temperature)
{
if (IsSimulation)
{
return SimBatchPhase(nameof(PreAdjustment_PushTemperature), CancellationToken.None).GetAwaiter().GetResult().Success;
}
const string operation = nameof(PreAdjustment_PushTemperature);
try
@@ -1932,6 +2064,10 @@ namespace TBF.Rig.BridgeComponents.GciBridge
public PreAdjustmentProcessResult PreAdjustment_TemperatureCalibrationDirect()
{
if (IsSimulation)
{
return SimBatchPhase("PreAdjustment_TemperatureCalibration", CancellationToken.None).GetAwaiter().GetResult();
}
const string operation = nameof(PreAdjustment_TemperatureCalibrationDirect);
try
@@ -1967,6 +2103,11 @@ namespace TBF.Rig.BridgeComponents.GciBridge
int slot,
CancellationToken token = default)
{
if (IsSimulation)
{
ValidateSimulationSlot(slot);
return await SimPhase("PreAdjustment_OffsetTest", slot, token).ConfigureAwait(false);
}
const string operation = nameof(PreAdjustment_OffsetTestAsync);
try
@@ -2012,6 +2153,10 @@ namespace TBF.Rig.BridgeComponents.GciBridge
public PreAdjustmentProcessResult PreAdjustment_OffsetTestDirect()
{
if (IsSimulation)
{
return SimBatchPhase("PreAdjustment_OffsetTest", CancellationToken.None).GetAwaiter().GetResult();
}
const string operation = nameof(PreAdjustment_OffsetTestDirect);
try
@@ -2047,6 +2192,11 @@ namespace TBF.Rig.BridgeComponents.GciBridge
int slot,
CancellationToken token = default)
{
if (IsSimulation)
{
ValidateSimulationSlot(slot);
return await SimPhase("PreAdjustment_Completion", slot, token).ConfigureAwait(false);
}
const string operation = nameof(PreAdjustment_CompletionAsync);
try
@@ -2092,6 +2242,10 @@ namespace TBF.Rig.BridgeComponents.GciBridge
public PreAdjustmentProcessResult PreAdjustment_CompletionDirect()
{
if (IsSimulation)
{
return SimBatchPhase("PreAdjustment_Completion", CancellationToken.None).GetAwaiter().GetResult();
}
const string operation = nameof(PreAdjustment_CompletionDirect);
try
@@ -2158,8 +2312,12 @@ namespace TBF.Rig.BridgeComponents.GciBridge
public List<string> GetAllRegisterNames()
{
if (IsSimulation)
{
return Simulation.Registers.Keys.Select(k => k.Substring(k.IndexOf(':') + 1)).Distinct().ToList();
}
EnsureExternalInterface();
return _gciEngine.gciExternalInterface.GetAllRegisterNames();
}
}
}
}
@@ -0,0 +1,70 @@
using System;
using System.Collections.Generic;
namespace TBF.Rig.BridgeComponents.GciBridge
{
// Source-editable simulation profiles. Configure before starting a test.
public sealed class GciSimulationProfile
{
public int DurationMs { get; set; } = 5000;
public bool Success { get; set; } = true;
public string ErrorMessage { get; set; } = "";
public string PcbId { get; set; } // Null generates a deterministic nine-digit ID per slot.
public string Password { get; set; } = "000000000000";
public string RawHex { get; set; } = "00000000";
public Dictionary<string, UInt32> CalibrationParams { get; set; } = new Dictionary<string, UInt32>();
internal GciSimulationProfile Snapshot()
{
if (DurationMs < 0) throw new ArgumentOutOfRangeException("DurationMs");
return new GciSimulationProfile
{
DurationMs = DurationMs, Success = Success, ErrorMessage = ErrorMessage,
PcbId = PcbId, Password = Password, RawHex = RawHex,
CalibrationParams = new Dictionary<string, UInt32>(CalibrationParams)
};
}
}
public sealed class GciSimulationSettings
{
public Dictionary<string, GciSimulationProfile> Operations { get; } = new Dictionary<string, GciSimulationProfile>(StringComparer.OrdinalIgnoreCase)
{
{ "MeterActivity", new GciSimulationProfile() },
{ "InitSlotAsync", new GciSimulationProfile() },
{ "UpdateSlotAsync", new GciSimulationProfile() },
{ "GetSlotAsync", new GciSimulationProfile() },
{ "CleanSlotAsync", new GciSimulationProfile() },
{ "CleanAllSlotsAsync", new GciSimulationProfile() },
{ "GetPcbIdAsync", new GciSimulationProfile() },
{ "ConnectAsync", new GciSimulationProfile() },
{ "LoginAsync", new GciSimulationProfile() },
{ "DisconnectAsync", new GciSimulationProfile() },
{ "SetPasswordAsync", new GciSimulationProfile() },
{ "ReadRegisterAsync", new GciSimulationProfile() },
{ "WriteRegisterAsync", new GciSimulationProfile() },
{ "GetPasswordAsync", new GciSimulationProfile() },
{ "GetPreAdjustmentCalibrationParamsAsync", new GciSimulationProfile() },
{ "ConnectFullPassLoginWithRetryAsync", new GciSimulationProfile() },
{ "Preadjustment_Initialization", new GciSimulationProfile() },
{ "PreAdjustment_Detect", new GciSimulationProfile() },
{ "PreAdjustment_Preparation", new GciSimulationProfile() },
{ "PreAdjustment_AmplitudeTest", new GciSimulationProfile() },
{ "PreAdjustment_TemperatureCalibration", new GciSimulationProfile() },
{ "PreAdjustment_PushTemperature", new GciSimulationProfile() },
{ "PreAdjustment_OffsetTest", new GciSimulationProfile() },
{ "PreAdjustment_Completion", new GciSimulationProfile() },
};
// Optional exact register profiles, e.g. WriteRegisterAsync:GENESISFLOW_TriggerActive.
public Dictionary<string, GciSimulationProfile> Registers { get; } = new Dictionary<string, GciSimulationProfile>(StringComparer.OrdinalIgnoreCase);
internal GciSimulationProfile Get(string operation, string register)
{
GciSimulationProfile profile;
if (register != null && Registers.TryGetValue(operation + ":" + register, out profile)) return profile.Snapshot();
if (!Operations.TryGetValue(operation, out profile)) throw new InvalidOperationException("Missing simulation profile: " + operation);
return profile.Snapshot();
}
}
}
@@ -51,7 +51,18 @@ namespace TBF.Rig.TestMethods.GenesisCommunication
System.Windows.Forms.Form modelessDlg;
private GenesisCommunicationDiagnosticsForm preadjustmentDiagnosticsForm;
private GenesisCommunicationDiagnosticsForm diagnosticsForm;
private void DiagnosticUi(Action action)
{
try
{
if (Program.MainWnd == null || Program.MainWnd.IsDisposed) return;
if (Program.MainWnd.InvokeRequired) Program.MainWnd.Invoke(action);
else action();
}
catch (Exception ex) { log.Warn("GCI diagnostic UI failed; execution continues.", ex); }
}
///
delegate void iPerlCommFormDlgt(GenesisCommunicationSeq myRef, TestMethod method, Test test, iPerlCommunicationParams testParams);
///
@@ -71,40 +82,6 @@ namespace TBF.Rig.TestMethods.GenesisCommunication
modelessDlg = null;
}
private delegate void PreadjustmentDiagnosticsFormDelegate(GenesisCommunicationSeq sequence, GciBridgeType bridge, string activity);
private void OpenPreadjustmentDiagnosticsForm(GenesisCommunicationSeq sequence, GciBridgeType bridge, string activity)
{
sequence.ClosePreadjustmentDiagnosticsForm();
sequence.preadjustmentDiagnosticsForm = new GenesisCommunicationDiagnosticsForm(bridge, activity);
sequence.preadjustmentDiagnosticsForm.Show();
}
private void ClosePreadjustmentDiagnosticsForm()
{
if (preadjustmentDiagnosticsForm == null)
return;
if (!preadjustmentDiagnosticsForm.IsDisposed)
preadjustmentDiagnosticsForm.Close();
preadjustmentDiagnosticsForm.Dispose();
preadjustmentDiagnosticsForm = null;
}
private void ShowPreadjustmentDiagnostics(GciBridgeType bridge, string activity)
{
Program.MainWnd.Invoke(new PreadjustmentDiagnosticsFormDelegate(OpenPreadjustmentDiagnosticsForm), new object[] { this, bridge, activity });
}
private void HidePreadjustmentDiagnostics()
{
if (Program.MainWnd == null || Program.MainWnd.IsDisposed)
return;
Program.MainWnd.Invoke(new Action(ClosePreadjustmentDiagnosticsForm));
}
/// <summary>
/// Flying start mass collection method sequence
@@ -127,7 +104,7 @@ namespace TBF.Rig.TestMethods.GenesisCommunication
processDataLoggingOp = new TBF.Rig.Operations.ProcessDataLoggingOp(processDataLogger, this, false);
iPerlCommunicationParams genesisTestParams = testParams as iPerlCommunicationParams;
if (genesisTestParams != null && IsPreadjustmentActivity(genesisTestParams.Activity))
if (genesisTestParams != null && (IsPreadjustmentActivity(genesisTestParams.Activity) || method.DebugLevel == DebugMode.Simulate))
{
return ExecutePreadjustment(test, method, genesisTestParams);
}
@@ -471,6 +448,52 @@ namespace TBF.Rig.TestMethods.GenesisCommunication
return new List<Event> { Event.Done };
}
private static bool ExecuteSimulatedMeterActivity(GciBridgeType bridge, IList<KeyValuePair<int, GenesisSmartReader>> readers, iPerlCommunicationParams parameters, out string response)
{
var tasks = readers.Select(item => System.Threading.Tasks.Task.Run(async () =>
{
int slot = item.Value.GetSlotNr;
string activity = parameters.Activity;
bool ok;
string message;
switch (activity)
{
case GenesisCommunicationForm.SlotInitializeStr:
case GenesisCommunicationForm.SlotUpdateStr:
var request = new GciPublicModels.GciInitSlotRequest { SlotId = slot };
var init = activity == GenesisCommunicationForm.SlotInitializeStr ? await bridge.InitSlotAsync(request) : await bridge.UpdateSlotAsync(request);
ok = init.Success; message = init.Message; break;
case GenesisCommunicationForm.SlotConnectStr:
var connected = await bridge.ConnectAsync(slot); ok = connected.Success; message = connected.Message; break;
case GenesisCommunicationForm.SlotPCBSlotStr:
var pcb = await bridge.GetPcbIdAsync(slot); ok = pcb.Success; message = pcb.ToString(); break;
case GenesisCommunicationForm.SlotSetPasswordStr:
var password = await bridge.SetPasswordAsync(slot, bridge.Simulation.Operations["SetPasswordAsync"].Password); ok = password.Success; message = password.Message; break;
case GenesisCommunicationForm.SlotLoginStr:
var login = await bridge.LoginAsync(slot); ok = login.Success; message = login.Message; break;
case GenesisCommunicationForm.SlotGroupedLoginStr:
var full = await bridge.ConnectFullPassLoginWithRetryAsync(slot); ok = full.Success; message = full.Message; break;
case GenesisCommunicationForm.SlotDisconnectStr:
var disconnected = await bridge.DisconnectAsync(slot); ok = disconnected.Success; message = disconnected.Message; break;
case GenesisCommunicationForm.SlotSetTestModeStr:
case GenesisCommunicationForm.SlotSetActiveModeStr:
var mode = await bridge.WriteRegisterAsync(slot, TBF.Rig.RegisterReaders.GenesisRegReader.communication.RadioService.LedMode, activity == GenesisCommunicationForm.SlotSetTestModeStr ? (byte)6 : (byte)0);
ok = mode.Success; message = mode.ErrorMessage; break;
case GenesisCommunicationForm.PrepareSlotQ3CalibrationStr:
case GenesisCommunicationForm.WriteSlotQ3CalibrationStr:
case GenesisCommunicationForm.CheckMeterPrepareStr:
case GenesisCommunicationForm.HoldSlotStr:
var aggregate = await bridge.SimulateMeterActivityAsync(activity, slot); ok = aggregate.Success; message = aggregate.ErrorMessage; break;
default:
throw new InvalidOperationException("No simulated Genesis activity mapping: " + activity);
}
return new KeyValuePair<bool, string>(ok, string.Format("Slot={0}, Success={1}, Message={2}", slot, ok, message));
})).ToArray();
var results = System.Threading.Tasks.Task.WhenAll(tasks).GetAwaiter().GetResult();
response = string.Join(Environment.NewLine, results.Select(r => r.Value));
return results.All(r => r.Key);
}
private static bool IsPreadjustmentActivity(string activity)
{
return string.Equals(activity, PreadjustmentInitializationStr, StringComparison.OrdinalIgnoreCase) ||
@@ -486,9 +509,12 @@ namespace TBF.Rig.TestMethods.GenesisCommunication
private IList<Event> ExecutePreadjustment(Test test, TestMethod method, iPerlCommunicationParams testParams)
{
DateTime startTime = DateTime.Now;
GenesisPreadjustmentBatchState batchState = null;
bool preadjustment = IsPreadjustmentActivity(testParams.Activity);
bool success = false;
string response = string.Empty;
List<KeyValuePair<int, GenesisSmartReader>> readers = new List<KeyValuePair<int, GenesisSmartReader>>();
List<KeyValuePair<int, GenesisSmartReader>> resultReaders = readers;
TestProgressEventArgs.SetEstimatedTimes(new int[] { 0, 0, 0, 30, 0, 30, 0, 0 });
Bridge.OnTestProgress(this, new TestProgressEventArgs(test, Progress.JustStarted));
@@ -506,7 +532,16 @@ namespace TBF.Rig.TestMethods.GenesisCommunication
try
{
readers = GetPreadjustmentReaders(test);
resultReaders = readers;
GciBridgeType bridge = GetCommonGciBridge(readers);
if (preadjustment) batchState = GenesisPreadjustmentBatchState.For(ProcessData.BatchRslts, bridge);
if (preadjustment)
{
foreach (int slot in batchState.Slots.Where(batchState.IsExcluded)) bridge.ExcludePreadjustmentSlot(slot);
readers = readers.Where(item => !batchState.IsExcluded(item.Value.GetSlotNr)).ToList();
}
if (method.DebugLevel == DebugMode.Simulate && !bridge.IsSimulation)
throw new InvalidOperationException("GenesisCommunication is simulated, but GCI Bridge is not in Simulate mode.");
preadjustmentLogger.Info(
"[PREADJUSTMENT] CONTEXT Test={0}, Activity={1}, Bridge={2}, Slots={3}, ReaderCount={4}",
@@ -516,11 +551,66 @@ namespace TBF.Rig.TestMethods.GenesisCommunication
string.Join(",", readers.Select(item => item.Value.GetSlotNr)),
readers.Count);
ShowPreadjustmentDiagnostics(bridge, testParams.Activity);
success = ExecutePreadjustmentActivity(bridge, readers, testParams, out response);
if (preadjustment) DiagnosticUi(() =>
{
diagnosticsForm = new GenesisCommunicationDiagnosticsForm(bridge, testParams.Activity, batchState);
if (!bridge.IsSimulation) diagnosticsForm.AttachProgress(bridge.gciExternalInterface._innerMeterAPI._progressProcess);
diagnosticsForm.Show(Program.MainWnd);
});
try
{
if (preadjustment) batchState.Start(readers.Select(item => item.Value.GetSlotNr), testParams.Activity);
if (readers.Count == 0) throw new InvalidOperationException("No eligible slots remain: failed slots are excluded for this batch.");
using (method.DebugLevel == DebugMode.Simulate ? bridge.BeginSimulation(new TBF.Rig.BridgeComponents.GciBridge.GciSimulationProfile { DurationMs = testParams.SimulationDurationMs, Success = testParams.SimulationSuccess, ErrorMessage = testParams.SimulationErrorMessage }) : null)
{
success = IsPreadjustmentActivity(testParams.Activity)
? ExecutePreadjustmentActivity(bridge, readers, testParams, out response)
: ExecuteSimulatedMeterActivity(bridge, readers, testParams, out response);
}
}
catch (Exception ex)
{
response = ex.Message;
throw;
}
finally
{
try
{
if (preadjustment && batchState != null)
{
foreach (var item in readers)
{
int slot = item.Value.GetSlotNr;
bool passed = success;
if (passed && !bridge.IsSimulation && !string.Equals(testParams.Activity, PreadjustmentInitializationStr, StringComparison.OrdinalIgnoreCase))
{
var controls = bridge.gciExternalInterface._innerMeterAPI._meterControls;
var control = controls == null ? null : controls.FirstOrDefault(c => c.Slot == slot);
passed = control != null && control.IsEnabled && !control.Failed;
}
batchState.Finish(slot, testParams.Activity, passed, response);
if (!passed) bridge.ExcludePreadjustmentSlot(slot);
}
}
}
finally
{
DiagnosticUi(() =>
{
if (diagnosticsForm != null)
{
diagnosticsForm.RefreshProgress();
diagnosticsForm.Dispose();
}
diagnosticsForm = null;
});
}
}
}
catch (Exception ex)
{
success = false;
response = ex.Message;
log.Error(string.Format("{0} failed.", testParams.Activity), ex);
@@ -533,12 +623,8 @@ namespace TBF.Rig.TestMethods.GenesisCommunication
(long)(DateTime.Now - startTime).TotalMilliseconds,
ex.Message);
}
finally
{
HidePreadjustmentDiagnostics();
}
UpdatePreadjustmentResult(test, method, readers, success, startTime);
UpdatePreadjustmentResult(test, method, resultReaders, success, startTime, preadjustment ? batchState : null);
if (success)
{
@@ -621,7 +707,7 @@ namespace TBF.Rig.TestMethods.GenesisCommunication
return commonBridge;
}
private static bool ExecutePreadjustmentActivity(GciBridgeType bridge, IList<KeyValuePair<int, GenesisSmartReader>> readers, iPerlCommunicationParams testParams, out string response)
private bool ExecutePreadjustmentActivity(GciBridgeType bridge, IList<KeyValuePair<int, GenesisSmartReader>> readers, iPerlCommunicationParams testParams, out string response)
{
preadjustmentLogger.Debug(
"[PREADJUSTMENT] DISPATCH Activity={0}, Bridge={1}, Slots={2}, Thread={3}",
@@ -658,6 +744,10 @@ namespace TBF.Rig.TestMethods.GenesisCommunication
meterControls.Add(meterControl);
}
DiagnosticUi(() =>
{
if (diagnosticsForm != null && !diagnosticsForm.IsDisposed) diagnosticsForm.AttachProgress(progress);
});
PublicModels.PreAdjustmentInitializationResult result = bridge.Preadjustment_Initialization(progress, meterControls);
response = result.ToString();
@@ -728,7 +818,7 @@ namespace TBF.Rig.TestMethods.GenesisCommunication
return processResult.Success;
}
private static void UpdatePreadjustmentResult(Test test, TestMethod method, IEnumerable<KeyValuePair<int, GenesisSmartReader>> readers, bool success, DateTime startTime)
private static void UpdatePreadjustmentResult(Test test, TestMethod method, IEnumerable<KeyValuePair<int, GenesisSmartReader>> readers, bool success, DateTime startTime, GenesisPreadjustmentBatchState batchState)
{
TestRslt testResult = ProcessData.BatchRslts.GetTestRslt(test.Name, test.Part);
if (testResult == null)
@@ -747,7 +837,7 @@ namespace TBF.Rig.TestMethods.GenesisCommunication
continue;
meterResult.WaterMeter.SerialNr = item.Value.SerialNr;
meterResult.Passed = success;
meterResult.Passed = success && (batchState == null || !batchState.IsExcluded(item.Value.GetSlotNr));
meterResult.TestDone = true;
preadjustmentLogger.Debug(
@@ -756,7 +846,7 @@ namespace TBF.Rig.TestMethods.GenesisCommunication
test.Part,
item.Key,
item.Value.GetSlotNr,
success);
meterResult.Passed);
}
}
@@ -0,0 +1,74 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
using GciBridgeType = TBF.Rig.BridgeComponents.GciBridge.GciBridge;
namespace TBF.Rig.TestMethods.GenesisCommunication
{
// Owned by the batch result object, never by the diagnostic window.
internal sealed class GenesisPreadjustmentBatchState
{
private static readonly ConditionalWeakTable<object, Dictionary<GciBridgeType, GenesisPreadjustmentBatchState>> batches = new ConditionalWeakTable<object, Dictionary<GciBridgeType, GenesisPreadjustmentBatchState>>();
private readonly object sync = new object();
private readonly Dictionary<int, Dictionary<string, string>> phases = new Dictionary<int, Dictionary<string, string>>();
private readonly Dictionary<int, Queue<string>> logs = new Dictionary<int, Queue<string>>();
private readonly HashSet<int> excluded = new HashSet<int>();
public static GenesisPreadjustmentBatchState For(object batch, GciBridgeType bridge)
{
lock (batches)
{
var states = batches.GetOrCreateValue(batch);
GenesisPreadjustmentBatchState state;
if (!states.TryGetValue(bridge, out state)) states.Add(bridge, state = new GenesisPreadjustmentBatchState());
return state;
}
}
public int[] Slots { get { lock (sync) return phases.Keys.ToArray(); } }
public bool IsExcluded(int slot) { lock (sync) return excluded.Contains(slot); }
public string Phase(int slot, string phase)
{
lock (sync)
{
Dictionary<string, string> values;
string value;
return phases.TryGetValue(slot, out values) && values.TryGetValue(phase, out value) ? value : "Pending";
}
}
public void Start(IEnumerable<int> slots, string phase)
{
lock (sync)
{
foreach (int slot in slots)
{
if (!phases.ContainsKey(slot)) phases.Add(slot, new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase));
if (excluded.Contains(slot)) continue;
phases[slot][phase] = "Running";
AddLog(slot, phase + " — START");
}
}
}
public void Finish(int slot, string phase, bool success, string message)
{
lock (sync)
{
if (!phases.ContainsKey(slot)) phases.Add(slot, new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase));
phases[slot][phase] = success ? "Passed" : "Failed";
if (!success) excluded.Add(slot);
AddLog(slot, phase + " — Success=" + success + ". " + message);
}
}
public void AddLog(int slot, string message)
{
if (slot <= 0) return;
lock (sync)
{
Queue<string> queue;
if (!logs.TryGetValue(slot, out queue)) logs.Add(slot, queue = new Queue<string>());
queue.Enqueue(DateTime.Now.ToString("HH:mm:ss.fff") + " " + message);
while (queue.Count > 1000) queue.Dequeue();
}
}
public string LogText(int slot) { lock (sync) return logs.ContainsKey(slot) ? string.Join(Environment.NewLine, logs[slot]) : ""; }
}
}
@@ -112,7 +112,7 @@ namespace TBF.Rig.TestMethods.GenesisCommunication
public IList<Event> Execute(Test test, int repetNr, bool isLastRepetition)
{
if (DebugLevel == DebugMode.Normal)
if (DebugLevel == DebugMode.Normal || DebugLevel == DebugMode.Simulate)
{
return (new GenesisCommunicationSeq()).Execute(test, repetNr, this, testMethodCfg.TestParams);
}
@@ -23,11 +23,25 @@ namespace TBF.Rig.TestMethods.GenesisCommunication
public IComponentCfgCtrl GetControl(IList<Config.Entities.Component> cmpntEntities) { return new TestMethodCfgCtrl(); }
//
public override IParamsProvider GetRuntimeTestParamsProvider() { return TestParams; }
public override IParamsProvider GetRuntimeTestParamsProvider()
{
var parameters = TestParams as iPerlCommunicationParams;
if (parameters != null) parameters.ShowSimulationParameters = SimulationColumnsEnabled();
return TestParams;
}
public override IParamsProvider CreateTestParamsProvider() { return new iPerlCommunicationParams(true); }
public override IParamsProvider GetUITestParamsProvider(Test test)
{
return (test.Method == Name) ? base.GetUITestParamsProvider(test) : null;
var provider = (test.Method == Name) ? base.GetUITestParamsProvider(test) : null;
var genesis = provider as iPerlCommunicationParams;
if (genesis != null) genesis.ShowSimulationParameters = SimulationColumnsEnabled();
return provider;
}
private bool SimulationColumnsEnabled()
{
var component = TbfComponents.FindComponent(Name) as TestMethod;
return component != null && component.DebugLevel == DebugMode.Simulate;
}
/// Private parameterless constructor invoked by all other (public) constructors
@@ -1,346 +1,103 @@
namespace TBF.Rig.TestMethods.GenesisCommunication
namespace TBF.Rig.TestMethods.GenesisCommunication
{
partial class GenesisCommunicationDiagnosticsForm
{
private System.ComponentModel.IContainer components = null;
private System.ComponentModel.IContainer components;
private System.Windows.Forms.SplitContainer verticalSplit;
private System.Windows.Forms.SplitContainer overviewSplit;
private System.Windows.Forms.DataGridView slotsGrid;
private System.Windows.Forms.DataGridView workersGrid;
private System.Windows.Forms.TabControl slotTabs;
private System.Windows.Forms.Timer refreshTimer;
private System.Windows.Forms.StatusStrip statusStrip;
private System.Windows.Forms.ToolStripStatusLabel statusLabel;
private System.Windows.Forms.ToolStrip toolbar;
private System.Windows.Forms.ToolStripButton refreshButton;
private System.Windows.Forms.ToolStripButton bridgeButton;
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
components.Dispose();
if (disposing)
{
ReleaseDiagnostics();
if (components != null) components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
private void InitializeComponent()
{
this.components = new System.ComponentModel.Container();
System.Windows.Forms.DataGridViewCellStyle lastActivityCellStyle = new System.Windows.Forms.DataGridViewCellStyle();
this.diagnosticsToolStrip = new System.Windows.Forms.ToolStrip();
this.activityToolStripLabel = new System.Windows.Forms.ToolStripLabel();
this.refreshToolStripButton = new System.Windows.Forms.ToolStripButton();
this.showBridgeToolStripButton = new System.Windows.Forms.ToolStripButton();
this.mainSplitContainer = new System.Windows.Forms.SplitContainer();
this.slotsGroupBox = new System.Windows.Forms.GroupBox();
this.slotsDataGridView = new System.Windows.Forms.DataGridView();
this.slotColumn = new System.Windows.Forms.DataGridViewTextBoxColumn();
this.selectedColumn = new System.Windows.Forms.DataGridViewCheckBoxColumn();
this.pcbIdColumn = new System.Windows.Forms.DataGridViewTextBoxColumn();
this.connectedColumn = new System.Windows.Forms.DataGridViewCheckBoxColumn();
this.loggedOnColumn = new System.Windows.Forms.DataGridViewCheckBoxColumn();
this.fwVersionColumn = new System.Windows.Forms.DataGridViewTextBoxColumn();
this.requestPortColumn = new System.Windows.Forms.DataGridViewTextBoxColumn();
this.requestPortTypeColumn = new System.Windows.Forms.DataGridViewTextBoxColumn();
this.streamingPortColumn = new System.Windows.Forms.DataGridViewTextBoxColumn();
this.interfaceVersionColumn = new System.Windows.Forms.DataGridViewTextBoxColumn();
this.workersGroupBox = new System.Windows.Forms.GroupBox();
this.workersDataGridView = new System.Windows.Forms.DataGridView();
this.workerSlotColumn = new System.Windows.Forms.DataGridViewTextBoxColumn();
this.workerNameColumn = new System.Windows.Forms.DataGridViewTextBoxColumn();
this.queueLengthColumn = new System.Windows.Forms.DataGridViewTextBoxColumn();
this.busyColumn = new System.Windows.Forms.DataGridViewCheckBoxColumn();
this.currentOperationColumn = new System.Windows.Forms.DataGridViewTextBoxColumn();
this.lastErrorColumn = new System.Windows.Forms.DataGridViewTextBoxColumn();
this.lastActivityColumn = new System.Windows.Forms.DataGridViewTextBoxColumn();
this.diagnosticsStatusStrip = new System.Windows.Forms.StatusStrip();
this.statusToolStripStatusLabel = new System.Windows.Forms.ToolStripStatusLabel();
this.verticalSplit = new System.Windows.Forms.SplitContainer();
this.overviewSplit = new System.Windows.Forms.SplitContainer();
this.slotsGrid = new System.Windows.Forms.DataGridView();
this.workersGrid = new System.Windows.Forms.DataGridView();
this.slotTabs = new System.Windows.Forms.TabControl();
this.refreshTimer = new System.Windows.Forms.Timer(this.components);
this.diagnosticsToolStrip.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.mainSplitContainer)).BeginInit();
this.mainSplitContainer.Panel1.SuspendLayout();
this.mainSplitContainer.Panel2.SuspendLayout();
this.mainSplitContainer.SuspendLayout();
this.slotsGroupBox.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.slotsDataGridView)).BeginInit();
this.workersGroupBox.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.workersDataGridView)).BeginInit();
this.diagnosticsStatusStrip.SuspendLayout();
this.statusStrip = new System.Windows.Forms.StatusStrip();
this.statusLabel = new System.Windows.Forms.ToolStripStatusLabel();
this.toolbar = new System.Windows.Forms.ToolStrip();
this.refreshButton = new System.Windows.Forms.ToolStripButton();
this.bridgeButton = new System.Windows.Forms.ToolStripButton();
((System.ComponentModel.ISupportInitialize)(this.verticalSplit)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.overviewSplit)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.slotsGrid)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.workersGrid)).BeginInit();
this.SuspendLayout();
//
// diagnosticsToolStrip
//
this.diagnosticsToolStrip.GripStyle = System.Windows.Forms.ToolStripGripStyle.Hidden;
this.diagnosticsToolStrip.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.activityToolStripLabel,
this.refreshToolStripButton,
this.showBridgeToolStripButton});
this.diagnosticsToolStrip.Location = new System.Drawing.Point(0, 0);
this.diagnosticsToolStrip.Name = "diagnosticsToolStrip";
this.diagnosticsToolStrip.Size = new System.Drawing.Size(1234, 25);
this.diagnosticsToolStrip.TabIndex = 0;
//
// activityToolStripLabel
//
this.activityToolStripLabel.Name = "activityToolStripLabel";
this.activityToolStripLabel.Size = new System.Drawing.Size(99, 22);
this.activityToolStripLabel.Text = "Running activity:";
//
// refreshToolStripButton
//
this.refreshToolStripButton.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Text;
this.refreshToolStripButton.Name = "refreshToolStripButton";
this.refreshToolStripButton.Size = new System.Drawing.Size(50, 22);
this.refreshToolStripButton.Text = "Refresh";
this.refreshToolStripButton.Click += new System.EventHandler(this.refreshToolStripButton_Click);
//
// showBridgeToolStripButton
//
this.showBridgeToolStripButton.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Text;
this.showBridgeToolStripButton.Name = "showBridgeToolStripButton";
this.showBridgeToolStripButton.Size = new System.Drawing.Size(124, 22);
this.showBridgeToolStripButton.Text = "Open GCI Bridge GUI";
this.showBridgeToolStripButton.Click += new System.EventHandler(this.showBridgeToolStripButton_Click);
//
// mainSplitContainer
//
this.mainSplitContainer.Dock = System.Windows.Forms.DockStyle.Fill;
this.mainSplitContainer.Location = new System.Drawing.Point(0, 25);
this.mainSplitContainer.Name = "mainSplitContainer";
this.mainSplitContainer.Panel1.Controls.Add(this.slotsGroupBox);
this.mainSplitContainer.Panel2.Controls.Add(this.workersGroupBox);
this.mainSplitContainer.Size = new System.Drawing.Size(1234, 534);
this.mainSplitContainer.SplitterDistance = 710;
this.mainSplitContainer.TabIndex = 1;
//
// slotsGroupBox
//
this.slotsGroupBox.Controls.Add(this.slotsDataGridView);
this.slotsGroupBox.Dock = System.Windows.Forms.DockStyle.Fill;
this.slotsGroupBox.Location = new System.Drawing.Point(0, 0);
this.slotsGroupBox.Name = "slotsGroupBox";
this.slotsGroupBox.Padding = new System.Windows.Forms.Padding(6);
this.slotsGroupBox.Size = new System.Drawing.Size(710, 534);
this.slotsGroupBox.TabIndex = 0;
this.slotsGroupBox.TabStop = false;
this.slotsGroupBox.Text = "GCI slots";
//
// slotsDataGridView
//
this.slotsDataGridView.AllowUserToAddRows = false;
this.slotsDataGridView.AllowUserToDeleteRows = false;
this.slotsDataGridView.AllowUserToResizeRows = false;
this.slotsDataGridView.AutoGenerateColumns = false;
this.slotsDataGridView.AutoSizeColumnsMode = System.Windows.Forms.DataGridViewAutoSizeColumnsMode.DisplayedCells;
this.slotsDataGridView.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize;
this.slotsDataGridView.Columns.AddRange(new System.Windows.Forms.DataGridViewColumn[] {
this.slotColumn,
this.selectedColumn,
this.pcbIdColumn,
this.connectedColumn,
this.loggedOnColumn,
this.fwVersionColumn,
this.requestPortColumn,
this.requestPortTypeColumn,
this.streamingPortColumn,
this.interfaceVersionColumn});
this.slotsDataGridView.Dock = System.Windows.Forms.DockStyle.Fill;
this.slotsDataGridView.Location = new System.Drawing.Point(6, 19);
this.slotsDataGridView.MultiSelect = false;
this.slotsDataGridView.Name = "slotsDataGridView";
this.slotsDataGridView.ReadOnly = true;
this.slotsDataGridView.RowHeadersWidth = 35;
this.slotsDataGridView.SelectionMode = System.Windows.Forms.DataGridViewSelectionMode.FullRowSelect;
this.slotsDataGridView.Size = new System.Drawing.Size(698, 509);
this.slotsDataGridView.TabIndex = 0;
//
// slot columns
//
this.slotColumn.DataPropertyName = "Slot";
this.slotColumn.HeaderText = "Slot";
this.slotColumn.Name = "slotColumn";
this.slotColumn.ReadOnly = true;
this.selectedColumn.DataPropertyName = "Selected";
this.selectedColumn.HeaderText = "Selected";
this.selectedColumn.Name = "selectedColumn";
this.selectedColumn.ReadOnly = true;
this.pcbIdColumn.DataPropertyName = "PcbId";
this.pcbIdColumn.HeaderText = "PCB ID";
this.pcbIdColumn.Name = "pcbIdColumn";
this.pcbIdColumn.ReadOnly = true;
this.connectedColumn.DataPropertyName = "IsConnected";
this.connectedColumn.HeaderText = "Connected";
this.connectedColumn.Name = "connectedColumn";
this.connectedColumn.ReadOnly = true;
this.loggedOnColumn.DataPropertyName = "IsLoggedOn";
this.loggedOnColumn.HeaderText = "Logged on";
this.loggedOnColumn.Name = "loggedOnColumn";
this.loggedOnColumn.ReadOnly = true;
this.fwVersionColumn.DataPropertyName = "FwVersion";
this.fwVersionColumn.HeaderText = "FW version";
this.fwVersionColumn.Name = "fwVersionColumn";
this.fwVersionColumn.ReadOnly = true;
this.requestPortColumn.DataPropertyName = "RequestPort";
this.requestPortColumn.HeaderText = "Request port";
this.requestPortColumn.Name = "requestPortColumn";
this.requestPortColumn.ReadOnly = true;
this.requestPortTypeColumn.DataPropertyName = "RequestPortType";
this.requestPortTypeColumn.HeaderText = "Request type";
this.requestPortTypeColumn.Name = "requestPortTypeColumn";
this.requestPortTypeColumn.ReadOnly = true;
this.streamingPortColumn.DataPropertyName = "StreamingPort";
this.streamingPortColumn.HeaderText = "Streaming port";
this.streamingPortColumn.Name = "streamingPortColumn";
this.streamingPortColumn.ReadOnly = true;
this.interfaceVersionColumn.DataPropertyName = "InterfaceVersion";
this.interfaceVersionColumn.HeaderText = "Interface version";
this.interfaceVersionColumn.Name = "interfaceVersionColumn";
this.interfaceVersionColumn.ReadOnly = true;
//
// workersGroupBox
//
this.workersGroupBox.Controls.Add(this.workersDataGridView);
this.workersGroupBox.Dock = System.Windows.Forms.DockStyle.Fill;
this.workersGroupBox.Location = new System.Drawing.Point(0, 0);
this.workersGroupBox.Name = "workersGroupBox";
this.workersGroupBox.Padding = new System.Windows.Forms.Padding(6);
this.workersGroupBox.Size = new System.Drawing.Size(520, 534);
this.workersGroupBox.TabIndex = 0;
this.workersGroupBox.TabStop = false;
this.workersGroupBox.Text = "GCI workers";
//
// workersDataGridView
//
this.workersDataGridView.AllowUserToAddRows = false;
this.workersDataGridView.AllowUserToDeleteRows = false;
this.workersDataGridView.AllowUserToResizeRows = false;
this.workersDataGridView.AutoGenerateColumns = false;
this.workersDataGridView.AutoSizeColumnsMode = System.Windows.Forms.DataGridViewAutoSizeColumnsMode.DisplayedCells;
this.workersDataGridView.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize;
this.workersDataGridView.Columns.AddRange(new System.Windows.Forms.DataGridViewColumn[] {
this.workerSlotColumn,
this.workerNameColumn,
this.queueLengthColumn,
this.busyColumn,
this.currentOperationColumn,
this.lastErrorColumn,
this.lastActivityColumn});
this.workersDataGridView.Dock = System.Windows.Forms.DockStyle.Fill;
this.workersDataGridView.Location = new System.Drawing.Point(6, 19);
this.workersDataGridView.MultiSelect = false;
this.workersDataGridView.Name = "workersDataGridView";
this.workersDataGridView.ReadOnly = true;
this.workersDataGridView.RowHeadersWidth = 35;
this.workersDataGridView.SelectionMode = System.Windows.Forms.DataGridViewSelectionMode.FullRowSelect;
this.workersDataGridView.Size = new System.Drawing.Size(508, 509);
this.workersDataGridView.TabIndex = 0;
//
// worker columns
//
this.workerSlotColumn.DataPropertyName = "Slot";
this.workerSlotColumn.HeaderText = "Slot";
this.workerSlotColumn.Name = "workerSlotColumn";
this.workerSlotColumn.ReadOnly = true;
this.workerNameColumn.DataPropertyName = "Name";
this.workerNameColumn.HeaderText = "Name";
this.workerNameColumn.Name = "workerNameColumn";
this.workerNameColumn.ReadOnly = true;
this.queueLengthColumn.DataPropertyName = "QueueLength";
this.queueLengthColumn.HeaderText = "Queue length";
this.queueLengthColumn.Name = "queueLengthColumn";
this.queueLengthColumn.ReadOnly = true;
this.busyColumn.DataPropertyName = "IsBusy";
this.busyColumn.HeaderText = "Busy";
this.busyColumn.Name = "busyColumn";
this.busyColumn.ReadOnly = true;
this.currentOperationColumn.DataPropertyName = "CurrentOperation";
this.currentOperationColumn.HeaderText = "Current operation";
this.currentOperationColumn.Name = "currentOperationColumn";
this.currentOperationColumn.ReadOnly = true;
this.lastErrorColumn.DataPropertyName = "LastError";
this.lastErrorColumn.HeaderText = "Last error";
this.lastErrorColumn.Name = "lastErrorColumn";
this.lastErrorColumn.ReadOnly = true;
this.lastActivityColumn.DataPropertyName = "LastActivity";
lastActivityCellStyle.Format = "G";
this.lastActivityColumn.DefaultCellStyle = lastActivityCellStyle;
this.lastActivityColumn.HeaderText = "Last activity";
this.lastActivityColumn.Name = "lastActivityColumn";
this.lastActivityColumn.ReadOnly = true;
//
// diagnosticsStatusStrip
//
this.diagnosticsStatusStrip.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.statusToolStripStatusLabel});
this.diagnosticsStatusStrip.Location = new System.Drawing.Point(0, 559);
this.diagnosticsStatusStrip.Name = "diagnosticsStatusStrip";
this.diagnosticsStatusStrip.Size = new System.Drawing.Size(1234, 22);
this.diagnosticsStatusStrip.TabIndex = 2;
//
// statusToolStripStatusLabel
//
this.statusToolStripStatusLabel.Name = "statusToolStripStatusLabel";
this.statusToolStripStatusLabel.Size = new System.Drawing.Size(122, 17);
this.statusToolStripStatusLabel.Text = "Waiting for GCI data...";
//
// refreshTimer
//
this.verticalSplit.Dock = System.Windows.Forms.DockStyle.Fill;
this.verticalSplit.Orientation = System.Windows.Forms.Orientation.Horizontal;
this.verticalSplit.Size = new System.Drawing.Size(1280, 720);
this.verticalSplit.SplitterDistance = 220;
this.verticalSplit.Name = "verticalSplit";
this.verticalSplit.Panel1.Controls.Add(this.overviewSplit);
this.verticalSplit.Panel2.Controls.Add(this.slotTabs);
this.overviewSplit.Dock = System.Windows.Forms.DockStyle.Fill;
this.overviewSplit.Size = new System.Drawing.Size(1280, 220);
this.overviewSplit.SplitterDistance = 640;
this.overviewSplit.Name = "overviewSplit";
this.overviewSplit.Panel1.Controls.Add(this.slotsGrid);
this.overviewSplit.Panel2.Controls.Add(this.workersGrid);
this.slotsGrid.Dock = System.Windows.Forms.DockStyle.Fill;
this.slotsGrid.Name = "slotsGrid";
this.slotsGrid.ReadOnly = true;
this.slotsGrid.AllowUserToAddRows = false;
this.slotsGrid.AllowUserToDeleteRows = false;
this.workersGrid.Dock = System.Windows.Forms.DockStyle.Fill;
this.workersGrid.Name = "workersGrid";
this.workersGrid.ReadOnly = true;
this.workersGrid.AllowUserToAddRows = false;
this.workersGrid.AllowUserToDeleteRows = false;
this.slotTabs.Dock = System.Windows.Forms.DockStyle.Fill;
this.slotTabs.Name = "slotTabs";
this.refreshTimer.Interval = 250;
this.refreshTimer.Tick += new System.EventHandler(this.refreshTimer_Tick);
//
// GenesisCommunicationDiagnosticsForm
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.refreshTimer.Tick += new System.EventHandler(this.RefreshTick);
this.statusStrip.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { this.statusLabel });
this.statusStrip.Dock = System.Windows.Forms.DockStyle.Bottom;
this.statusStrip.Name = "statusStrip";
this.statusLabel.Text = "Waiting for slot data";
this.Controls.Add(this.verticalSplit);
this.Controls.Add(this.statusStrip);
this.refreshButton.Text = "Refresh";
this.refreshButton.Click += new System.EventHandler(this.RefreshTick);
this.bridgeButton.Text = "Open GCI Bridge GUI";
this.bridgeButton.Click += new System.EventHandler(this.OpenBridge);
this.toolbar.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { this.refreshButton, this.bridgeButton });
this.toolbar.Dock = System.Windows.Forms.DockStyle.Top;
this.Controls.Add(this.toolbar);
this.ClientSize = new System.Drawing.Size(1280, 742);
this.MinimumSize = new System.Drawing.Size(900, 550);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(1234, 581);
this.Controls.Add(this.mainSplitContainer);
this.Controls.Add(this.diagnosticsStatusStrip);
this.Controls.Add(this.diagnosticsToolStrip);
this.MinimizeBox = false;
this.MinimumSize = new System.Drawing.Size(900, 400);
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.StartPosition = System.Windows.Forms.FormStartPosition.Manual;
this.Name = "GenesisCommunicationDiagnosticsForm";
this.ShowInTaskbar = false;
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
this.Text = "Genesis Communication - GCI diagnostics";
this.FormClosed += new System.Windows.Forms.FormClosedEventHandler(this.GenesisCommunicationDiagnosticsForm_FormClosed);
this.Load += new System.EventHandler(this.GenesisCommunicationDiagnosticsForm_Load);
this.diagnosticsToolStrip.ResumeLayout(false);
this.diagnosticsToolStrip.PerformLayout();
this.mainSplitContainer.Panel1.ResumeLayout(false);
this.mainSplitContainer.Panel2.ResumeLayout(false);
((System.ComponentModel.ISupportInitialize)(this.mainSplitContainer)).EndInit();
this.mainSplitContainer.ResumeLayout(false);
this.slotsGroupBox.ResumeLayout(false);
((System.ComponentModel.ISupportInitialize)(this.slotsDataGridView)).EndInit();
this.workersGroupBox.ResumeLayout(false);
((System.ComponentModel.ISupportInitialize)(this.workersDataGridView)).EndInit();
this.diagnosticsStatusStrip.ResumeLayout(false);
this.diagnosticsStatusStrip.PerformLayout();
this.Text = "Genesis diagnostics";
this.Load += new System.EventHandler(this.FormLoaded);
((System.ComponentModel.ISupportInitialize)(this.slotsGrid)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.workersGrid)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.overviewSplit)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.verticalSplit)).EndInit();
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.ToolStrip diagnosticsToolStrip;
private System.Windows.Forms.ToolStripLabel activityToolStripLabel;
private System.Windows.Forms.ToolStripButton refreshToolStripButton;
private System.Windows.Forms.ToolStripButton showBridgeToolStripButton;
private System.Windows.Forms.SplitContainer mainSplitContainer;
private System.Windows.Forms.GroupBox slotsGroupBox;
private System.Windows.Forms.DataGridView slotsDataGridView;
private System.Windows.Forms.GroupBox workersGroupBox;
private System.Windows.Forms.DataGridView workersDataGridView;
private System.Windows.Forms.StatusStrip diagnosticsStatusStrip;
private System.Windows.Forms.ToolStripStatusLabel statusToolStripStatusLabel;
private System.Windows.Forms.Timer refreshTimer;
private System.Windows.Forms.DataGridViewTextBoxColumn slotColumn;
private System.Windows.Forms.DataGridViewCheckBoxColumn selectedColumn;
private System.Windows.Forms.DataGridViewTextBoxColumn pcbIdColumn;
private System.Windows.Forms.DataGridViewCheckBoxColumn connectedColumn;
private System.Windows.Forms.DataGridViewCheckBoxColumn loggedOnColumn;
private System.Windows.Forms.DataGridViewTextBoxColumn fwVersionColumn;
private System.Windows.Forms.DataGridViewTextBoxColumn requestPortColumn;
private System.Windows.Forms.DataGridViewTextBoxColumn requestPortTypeColumn;
private System.Windows.Forms.DataGridViewTextBoxColumn streamingPortColumn;
private System.Windows.Forms.DataGridViewTextBoxColumn interfaceVersionColumn;
private System.Windows.Forms.DataGridViewTextBoxColumn workerSlotColumn;
private System.Windows.Forms.DataGridViewTextBoxColumn workerNameColumn;
private System.Windows.Forms.DataGridViewTextBoxColumn queueLengthColumn;
private System.Windows.Forms.DataGridViewCheckBoxColumn busyColumn;
private System.Windows.Forms.DataGridViewTextBoxColumn currentOperationColumn;
private System.Windows.Forms.DataGridViewTextBoxColumn lastErrorColumn;
private System.Windows.Forms.DataGridViewTextBoxColumn lastActivityColumn;
}
}
@@ -1,78 +1,218 @@
using System;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Windows.Forms;
using CordonelPreadjustmentUi;
using CordonelPreadjustmentUi.Processes.Itinerary;
using Xylem.Common.Ui.CordonelPreadjustmentUi;
using GciBridgeType = TBF.Rig.BridgeComponents.GciBridge.GciBridge;
using GciPublicModels = GenesisCordonelInterface.API.PublicModels;
namespace TBF.Rig.TestMethods.GenesisCommunication
{
/// <summary>
/// Displays live GCI slot and worker information while a GenesisCommunication
/// preadjustment activity is running.
/// </summary>
public partial class GenesisCommunicationDiagnosticsForm : Form
{
private readonly GciBridgeType bridge;
private readonly string activity;
private GciBridgeType bridge;
private string activity;
private ProcessProgress progress;
private GenesisPreadjustmentBatchState batchState;
private readonly Dictionary<int, Dictionary<string, Label>> phaseLabels = new Dictionary<int, Dictionary<string, Label>>();
private readonly Dictionary<int, TabPage> pages = new Dictionary<int, TabPage>();
private readonly Dictionary<int, Label> states = new Dictionary<int, Label>();
private readonly Dictionary<int, Label> activePhases = new Dictionary<int, Label>();
private readonly Dictionary<int, RichTextBox> memos = new Dictionary<int, RichTextBox>();
private readonly object logLock = new object();
private readonly Queue<KeyValuePair<int, string>> pending = new Queue<KeyValuePair<int, string>>();
private bool acceptingLogs;
private int dropped;
private static readonly string[] Phases = { "Initialization", "Detect", "Preparation", "Amplitude Test", "Temperature Calibration", "Push Temperature", "Offset Test", "Completion" };
public GenesisCommunicationDiagnosticsForm(GciBridgeType bridge, string activity)
public GenesisCommunicationDiagnosticsForm()
{
if (bridge == null)
throw new ArgumentNullException("bridge");
this.bridge = bridge;
this.activity = activity ?? string.Empty;
InitializeComponent();
activityToolStripLabel.Text = "Running activity: " + this.activity;
slotTabs.DrawMode = TabDrawMode.OwnerDrawFixed;
slotTabs.DrawItem += DrawSlotTab;
slotTabs.ItemSize = new Size(100, 28);
slotTabs.SizeMode = TabSizeMode.Fixed;
}
private void GenesisCommunicationDiagnosticsForm_Load(object sender, EventArgs e)
public GenesisCommunicationDiagnosticsForm(GciBridgeType bridge, string activity) : this(bridge, activity, new GenesisPreadjustmentBatchState()) { }
internal GenesisCommunicationDiagnosticsForm(GciBridgeType bridge, string activity, GenesisPreadjustmentBatchState batchState) : this()
{
RefreshDiagnostics();
this.batchState = batchState;
this.bridge = bridge;
this.activity = activity;
Text = "Genesis diagnostics — " + activity;
acceptingLogs = true;
if (bridge.IsSimulation) bridge.SimulationLog += OnSimulationLog;
}
public void AttachProgress(ProcessProgress value)
{
if (ReferenceEquals(progress, value)) return;
if (progress != null) progress.OnDebugMessageChanged -= OnDebugMessage;
progress = value;
if (progress != null) progress.OnDebugMessageChanged += OnDebugMessage;
}
private void OnDebugMessage(object sender, EventArgsDebug e)
{
if (!e.Slot.HasValue || e.Slot.Value <= 0) return;
lock (logLock)
{
if (!acceptingLogs) return;
if (pending.Count >= 5000) { pending.Dequeue(); dropped++; }
pending.Enqueue(new KeyValuePair<int, string>(e.Slot.Value, string.Format("{0:HH:mm:ss.fff} [{1}] {2}", DateTime.Now, e.Source, e.Value)));
}
}
private void OnSimulationLog(int slot, string message)
{
lock (logLock)
{
if (!acceptingLogs) return;
if (pending.Count >= 5000) { pending.Dequeue(); dropped++; }
pending.Enqueue(new KeyValuePair<int, string>(slot, DateTime.Now.ToString("HH:mm:ss.fff") + " " + message));
}
}
private void RefreshTick(object sender, EventArgs e)
{
if (bridge == null) return;
try
{
var api = bridge.IsSimulation ? null : bridge.gciExternalInterface;
var slots = bridge.GetMeterBatchDebugStatuses();
slotsGrid.DataSource = slots;
workersGrid.DataSource = bridge.GetWorkerDebugStatuses();
var selected = new HashSet<int>((slots ?? new List<GenesisCordonelInterface.API.PublicModels.MeterBatchDebugStatus>()).Where(s => s.Selected).Select(s => s.Slot));
foreach (int slot in batchState.Slots.Where(batchState.IsExcluded)) selected.Add(slot);
foreach (int slot in batchState.Slots.Where(slot => batchState.Phase(slot, activity) == "Running")) selected.Add(slot);
foreach (int slot in selected.OrderBy(s => s))
{
if (!pages.ContainsKey(slot)) CreateSlot(slot);
if (!slotTabs.TabPages.Contains(pages[slot])) slotTabs.TabPages.Add(pages[slot]);
bool excluded = batchState.IsExcluded(slot);
states[slot].Text = excluded ? "Excluded from further preadjustment phases in this batch" : activity;
states[slot].BackColor = excluded ? Color.FromArgb(253, 226, 226) : Color.FromArgb(255, 237, 213);
states[slot].ForeColor = excluded ? Color.DarkRed : Color.FromArgb(124, 65, 12);
foreach (var phase in phaseLabels[slot])
{
string state = batchState.Phase(slot, "Preadjustment " + phase.Key);
phase.Value.Text = phase.Key + Environment.NewLine + (excluded && state == "Pending" ? "Excluded" : state);
phase.Value.BackColor = state == "Passed" ? Color.FromArgb(209, 250, 229) : state == "Failed" ? Color.FromArgb(254, 202, 202) : state == "Running" ? Color.FromArgb(255, 214, 153) : Color.FromArgb(235, 239, 244);
phase.Value.ForeColor = state == "Passed" ? Color.FromArgb(6, 95, 70) : state == "Failed" ? Color.FromArgb(153, 27, 27) : state == "Running" ? Color.FromArgb(146, 64, 14) : Color.FromArgb(80, 95, 115);
}
foreach (DataGridViewRow row in slotsGrid.Rows)
{
if (row.Cells["Slot"].Value != null && Convert.ToInt32(row.Cells["Slot"].Value) == slot && excluded)
{
row.Cells["Selected"].Value = false;
row.DefaultCellStyle.BackColor = Color.FromArgb(253, 226, 226);
}
}
}
foreach (int slot in pages.Keys.Where(s => !selected.Contains(s)).ToArray()) slotTabs.TabPages.Remove(pages[slot]);
slotTabs.Invalidate();
statusLabel.Text = string.Format("Selected slots: {0} | Refresh: {1:HH:mm:ss} | Dropped log messages: {2}", selected.Count, DateTime.Now, dropped);
}
catch (Exception ex) { statusLabel.Text = "Diagnostics: " + ex.Message; }
FlushLogs();
}
private void CreateSlot(int slot)
{
var page = new TabPage("Slot " + slot) { Tag = slot, BackColor = Color.White };
phaseLabels[slot] = new Dictionary<string, Label>();
var phasePanel = new FlowLayoutPanel { Dock = DockStyle.Top, Height = 100, AutoScroll = true };
foreach (string phase in Phases)
{
bool current = string.Equals(activity, "Preadjustment " + phase, StringComparison.OrdinalIgnoreCase);
var label = new Label { Text = phase + (current ? "\nRunning" : "\nPending"), AutoSize = false, Size = new Size(145, 60), TextAlign = ContentAlignment.MiddleCenter, BackColor = Color.FromArgb(235, 239, 244), Margin = new Padding(5), Font = new Font("Segoe UI", 9F, FontStyle.Bold) };
phasePanel.Controls.Add(label);
phaseLabels[slot].Add(phase, label);
if (current) activePhases[slot] = label;
}
var state = new Label { Dock = DockStyle.Top, Height = 30, TextAlign = ContentAlignment.MiddleLeft };
var memo = new RichTextBox { Dock = DockStyle.Fill, ReadOnly = true, WordWrap = false, DetectUrls = false, BackColor = Color.White, Font = new Font("Consolas", 9), HideSelection = false };
page.Controls.Add(memo);
page.Controls.Add(state);
page.Controls.Add(phasePanel);
pages.Add(slot, page);
states.Add(slot, state);
memos.Add(slot, memo);
}
private void FlushLogs()
{
var batch = new List<KeyValuePair<int, string>>();
lock (logLock) { while (pending.Count > 0 && batch.Count < 500) batch.Add(pending.Dequeue()); }
foreach (var entry in batch) batchState.AddLog(entry.Key, entry.Value);
foreach (var pair in memos)
{
string text = batchState.LogText(pair.Key);
if (pair.Value.Text == text) continue;
bool atEnd = pair.Value.SelectionStart + pair.Value.SelectionLength >= pair.Value.TextLength;
int selection = pair.Value.SelectionStart;
pair.Value.Text = text;
pair.Value.Select(atEnd ? pair.Value.TextLength : Math.Min(selection, pair.Value.TextLength), 0);
if (atEnd) pair.Value.ScrollToCaret();
}
}
private void DrawSlotTab(object sender, DrawItemEventArgs e)
{
var page = slotTabs.TabPages[e.Index];
int slot = (int)page.Tag;
bool failed = batchState != null && batchState.IsExcluded(slot);
Color color = failed ? Color.FromArgb(185, 28, 28) : e.Index == slotTabs.SelectedIndex ? Color.FromArgb(30, 64, 105) : Color.FromArgb(226, 232, 240);
using (var brush = new SolidBrush(color)) e.Graphics.FillRectangle(brush, e.Bounds);
TextRenderer.DrawText(e.Graphics, page.Text + (failed ? " !" : ""), Font, e.Bounds, failed || e.Index == slotTabs.SelectedIndex ? Color.White : Color.FromArgb(30, 41, 59), TextFormatFlags.HorizontalCenter | TextFormatFlags.VerticalCenter);
}
public void RefreshProgress()
{
if (IsDisposed) return;
RefreshTick(this, EventArgs.Empty);
Update();
}
private void FormLoaded(object sender, EventArgs e)
{
if (bridge == null) return;
// Fit the results region, keeping the top toolbar and right TBF controls visible.
var ownerArea = Owner == null ? Screen.FromControl(this).WorkingArea : Owner.RectangleToScreen(Owner.ClientRectangle);
var workArea = Screen.FromControl(Owner ?? this).WorkingArea;
int topInset = (int)Math.Round(ownerArea.Height * 0.09);
int rightInset = (int)Math.Round(ownerArea.Width * 0.125);
StartPosition = FormStartPosition.Manual;
WindowState = FormWindowState.Normal;
MinimumSize = new Size(640, 360);
Bounds = Rectangle.Intersect(workArea, new Rectangle(ownerArea.Left, ownerArea.Top + topInset, ownerArea.Width - rightInset, ownerArea.Height - topInset - 24));
RefreshTick(sender, e);
refreshTimer.Start();
}
private void GenesisCommunicationDiagnosticsForm_FormClosed(object sender, FormClosedEventArgs e)
private void OpenBridge(object sender, EventArgs e)
{
try { if (bridge != null) bridge.ShowGui(); }
catch (Exception ex) { statusLabel.Text = "GCI GUI: " + ex.Message; }
}
private void ReleaseDiagnostics()
{
refreshTimer.Stop();
}
private void refreshTimer_Tick(object sender, EventArgs e)
{
RefreshDiagnostics();
}
private void refreshToolStripButton_Click(object sender, EventArgs e)
{
RefreshDiagnostics();
}
private void showBridgeToolStripButton_Click(object sender, EventArgs e)
{
bridge.ShowGui();
}
private void RefreshDiagnostics()
{
try
lock (logLock) { acceptingLogs = false; }
if (batchState != null)
{
var api = bridge.gciExternalInterface;
List<GciPublicModels.MeterBatchDebugStatus> slotStatuses = api == null
? new List<GciPublicModels.MeterBatchDebugStatus>()
: api.GetMeterBatchDebugStatuses() ?? new List<GciPublicModels.MeterBatchDebugStatus>();
List<GciPublicModels.WorkerDebugStatus> workerStatuses = api == null
? new List<GciPublicModels.WorkerDebugStatus>()
: api.GetWorkerDebugStatuses() ?? new List<GciPublicModels.WorkerDebugStatus>();
slotsDataGridView.DataSource = slotStatuses;
workersDataGridView.DataSource = workerStatuses;
statusToolStripStatusLabel.Text = string.Format("Updated {0:HH:mm:ss.fff} | Slots: {1} | Workers: {2}", DateTime.Now, slotStatuses.Count, workerStatuses.Count);
}
catch (Exception ex)
{
statusToolStripStatusLabel.Text = "Diagnostic refresh failed: " + ex.Message;
// No producer can append after acceptingLogs is cleared.
do { FlushLogs(); } while (pending.Count > 0);
}
AttachProgress(null);
if (bridge != null) bridge.SimulationLog -= OnSimulationLog;
foreach (var page in pages.Values) page.Dispose();
pages.Clear();
}
}
}
@@ -1,61 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="resmimetype"><value>text/microsoft-resx</value></resheader>
<resheader name="version"><value>2.0</value></resheader>
<resheader name="reader"><value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value></resheader>
<resheader name="writer"><value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value></resheader>
</root>
@@ -10,6 +10,7 @@ using Config.Entities;
using TBF.Resources;
using TBF.Rig.Generic;
using TBF.Rig.TestMethods.iPerlCommunication;
using Xylem.Common.Logic.ProductionOrderCore.OrderData;
namespace TBF.Rig.TestMethods.GenesisCommunication
{
@@ -29,6 +30,11 @@ namespace TBF.Rig.TestMethods.GenesisCommunication
public bool SimultWithNext;
public string MeterSize = "DN50";
public float Temperature = 20.0f;
public int SimulationDurationMs = 5000;
public bool SimulationSuccess = true;
public string SimulationErrorMessage = "";
[XmlIgnore]
public bool ShowSimulationParameters;
public override void InitializeAll()
{
@@ -37,6 +43,9 @@ namespace TBF.Rig.TestMethods.GenesisCommunication
SimultWithNext = false;
MeterSize = "DN50";
Temperature = 20.0f;
SimulationDurationMs = 5000;
SimulationSuccess = true;
SimulationErrorMessage = "";
}
@@ -47,9 +56,12 @@ namespace TBF.Rig.TestMethods.GenesisCommunication
Strings.Simultaneous_with_next_step,
"Meter size",
"Temperature [°C]",
"Simulation duration [ms]",
"Simulation Success",
"Simulation ErrorMessage",
};
public override string ParamName(int i) { return paramNames[i]; }
public override int ParamsCount() { return paramNames.Length; }
public override int ParamsCount() { return ShowSimulationParameters ? paramNames.Length : 5; }
public override ICollection<string> ParamValues(int i)
{
@@ -140,14 +152,14 @@ namespace TBF.Rig.TestMethods.GenesisCommunication
return retVal;
}
else if (i == 1 || i == 2)
else if (i == 1 || i == 2 || i == 6)
{
return new string[] { Strings.yes, Strings.no };
}
else if (i == 3)
{
var meterSizes = new List<string>(System.Enum.GetNames(typeof(Xylem.Common.Logic.ProductionOrderCore.OrderData.MeterSize)));
meterSizes.Remove(Xylem.Common.Logic.ProductionOrderCore.OrderData.MeterSize.NA.ToString());
var meterSizes = new List<string>(System.Enum.GetNames(typeof(MeterSize)));
meterSizes.RemoveAll(value => value.EndsWith("MAX", System.StringComparison.OrdinalIgnoreCase));
return meterSizes;
}
@@ -163,6 +175,9 @@ namespace TBF.Rig.TestMethods.GenesisCommunication
case 2: return (SimultWithNext ? Strings.yes : Strings.no);
case 3: return MeterSize;
case 4: return Temperature.ToString();
case 5: return SimulationDurationMs.ToString();
case 6: return SimulationSuccess ? Strings.yes : Strings.no;
case 7: return SimulationErrorMessage;
default: return string.Empty;
}
}
@@ -176,6 +191,9 @@ namespace TBF.Rig.TestMethods.GenesisCommunication
case 2: SimultWithNext = strValue.ToLower().Equals(Strings.yes.ToLower()); return CfgUpdateFlags.None;
case 3: MeterSize = strValue; return CfgUpdateFlags.None;
case 4: Temperature = Utils.ParseSFloat(strValue); return CfgUpdateFlags.None;
case 5: SimulationDurationMs = int.Parse(strValue); return CfgUpdateFlags.None;
case 6: SimulationSuccess = strValue.Equals(Strings.yes, System.StringComparison.OrdinalIgnoreCase); return CfgUpdateFlags.None;
case 7: SimulationErrorMessage = strValue; return CfgUpdateFlags.None;
default: return CfgUpdateFlags.None;
}
}
@@ -191,13 +209,19 @@ namespace TBF.Rig.TestMethods.GenesisCommunication
return true;
case 1:
case 2:
case 6:
if (strValue.Equals(Strings.yes) || strValue.Equals(Strings.no)) return true;
break;
case 3:
return System.Enum.TryParse(strValue, true, out Xylem.Common.Logic.ProductionOrderCore.OrderData.MeterSize meterSize) && meterSize != Xylem.Common.Logic.ProductionOrderCore.OrderData.MeterSize.NA;
MeterSize meterSize;
return System.Enum.TryParse(strValue, true, out meterSize) && !meterSize.ToString().EndsWith("MAX", System.StringComparison.OrdinalIgnoreCase);
case 4:
if (Utils.TryParseSFloat(strValue, out temperature) && temperature >= -20.0f && temperature <= 100.0f) return true;
break;
case 5:
int duration;
return int.TryParse(strValue, out duration) && duration >= 0;
case 7: return true;
default:
message = "Invalid index";
return false;
@@ -214,12 +238,16 @@ namespace TBF.Rig.TestMethods.GenesisCommunication
prms.SimultWithNext = this.SimultWithNext;
prms.MeterSize = this.MeterSize;
prms.Temperature = this.Temperature;
prms.SimulationDurationMs = SimulationDurationMs;
prms.SimulationSuccess = SimulationSuccess;
prms.SimulationErrorMessage = SimulationErrorMessage;
}
public IParamsProvider Clone()
{
iPerlCommunicationParams pars = new iPerlCommunicationParams();
CopyContentTo(pars);
pars.ShowSimulationParameters = ShowSimulationParameters;
return pars;
}
+3
View File
@@ -249,6 +249,7 @@
<Compile Include="Rig\Ambient\Greco\Factory.cs" />
<Compile Include="Rig\BridgeComponents\GciBridge\Factory.cs" />
<Compile Include="Rig\BridgeComponents\GciBridge\GciBridge.cs" />
<Compile Include="Rig\BridgeComponents\GciBridge\GciBridge.Simulation.cs" />
<Compile Include="Rig\BridgeComponents\GciBridge\GciBridgeCfg.cs" />
<Compile Include="Rig\BridgeComponents\GciBridge\GciBridgeCfgCtrl.cs">
<SubType>UserControl</SubType>
@@ -257,6 +258,7 @@
<DependentUpon>GciBridgeCfgCtrl.cs</DependentUpon>
</Compile>
<Compile Include="Rig\BridgeComponents\GciBridge\GciBridgeOp.cs" />
<Compile Include="Rig\BridgeComponents\GciBridge\GciSimulationSettings.cs" />
<Compile Include="Rig\BridgeComponents\GciBridge\Interfaces\PublicModels.cs" />
<Compile Include="Rig\BridgeComponents\GciBridge\UI\Debug\DebugModels.cs" />
<Compile Include="Rig\BridgeComponents\GciBridge\UI\Debug\MeterBatchConfigPanel.cs">
@@ -2001,6 +2003,7 @@
<Compile Include="Rig\TestMethods\AllyCalibration\TestMethodParams.cs" />
<Compile Include="Rig\TestMethods\GenesisCommunication\Factory.cs" />
<Compile Include="Rig\TestMethods\GenesisCommunication\GenesisCommunicationSeq.cs" />
<Compile Include="Rig\TestMethods\GenesisCommunication\GenesisPreadjustmentBatchState.cs" />
<Compile Include="Rig\TestMethods\GenesisCommunication\iPerlCommunicationParams.cs" />
<Compile Include="Rig\TestMethods\GenesisCommunication\SequenceConditionOp.cs" />
<Compile Include="Rig\TestMethods\GenesisCommunication\TestMethod.cs" />