diff --git a/AppDiagnostic.Logging/bin/Debug/net472/AppDiagnostic.Logging.dll b/AppDiagnostic.Logging/bin/Debug/net472/AppDiagnostic.Logging.dll index fa3b3ef1c..178529b66 100644 Binary files a/AppDiagnostic.Logging/bin/Debug/net472/AppDiagnostic.Logging.dll and b/AppDiagnostic.Logging/bin/Debug/net472/AppDiagnostic.Logging.dll differ diff --git a/AppDiagnostic.Logging/bin/Debug/net472/AppDiagnostic.Logging.pdb b/AppDiagnostic.Logging/bin/Debug/net472/AppDiagnostic.Logging.pdb index c8da8e1d1..5325f29ac 100644 Binary files a/AppDiagnostic.Logging/bin/Debug/net472/AppDiagnostic.Logging.pdb and b/AppDiagnostic.Logging/bin/Debug/net472/AppDiagnostic.Logging.pdb differ diff --git a/AppDiagnostic.Logging/bin/Release/net472/AppDiagnostic.Logging.dll b/AppDiagnostic.Logging/bin/Release/net472/AppDiagnostic.Logging.dll index 92ba99691..42b3c07eb 100644 Binary files a/AppDiagnostic.Logging/bin/Release/net472/AppDiagnostic.Logging.dll and b/AppDiagnostic.Logging/bin/Release/net472/AppDiagnostic.Logging.dll differ diff --git a/AppDiagnostic.Logging/bin/Release/net472/AppDiagnostic.Logging.pdb b/AppDiagnostic.Logging/bin/Release/net472/AppDiagnostic.Logging.pdb index 20f7774dc..84738e995 100644 Binary files a/AppDiagnostic.Logging/bin/Release/net472/AppDiagnostic.Logging.pdb and b/AppDiagnostic.Logging/bin/Release/net472/AppDiagnostic.Logging.pdb differ diff --git a/AppDiagnostic.Logging/obj/Debug/net472/AppDiagnostic.Logging.AssemblyInfo.cs b/AppDiagnostic.Logging/obj/Debug/net472/AppDiagnostic.Logging.AssemblyInfo.cs index d8bf95e08..e08d8f20a 100644 --- a/AppDiagnostic.Logging/obj/Debug/net472/AppDiagnostic.Logging.AssemblyInfo.cs +++ b/AppDiagnostic.Logging/obj/Debug/net472/AppDiagnostic.Logging.AssemblyInfo.cs @@ -14,7 +14,7 @@ using System.Reflection; [assembly: System.Reflection.AssemblyCompanyAttribute("AppDiagnostic.Logging")] [assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")] [assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")] -[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+8c77df207addcf9ed024240630cb0c32c1fde253")] +[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+73c8fecdf26ee704bb58f3b6ad4a3379d7cfbe4b")] [assembly: System.Reflection.AssemblyProductAttribute("AppDiagnostic.Logging")] [assembly: System.Reflection.AssemblyTitleAttribute("AppDiagnostic.Logging")] [assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")] diff --git a/AppDiagnostic.Logging/obj/Debug/net472/AppDiagnostic.Logging.AssemblyInfoInputs.cache b/AppDiagnostic.Logging/obj/Debug/net472/AppDiagnostic.Logging.AssemblyInfoInputs.cache index 226b27b48..48beda22d 100644 --- a/AppDiagnostic.Logging/obj/Debug/net472/AppDiagnostic.Logging.AssemblyInfoInputs.cache +++ b/AppDiagnostic.Logging/obj/Debug/net472/AppDiagnostic.Logging.AssemblyInfoInputs.cache @@ -1 +1 @@ -310753f2dd2c5b12720ac2b377209bbf1d64c37a00b3b643b72c1104163a0fd7 +dac526eb412111d5458e461c4bd83555b5401d4aabe90cd895bf1756693cdd5a diff --git a/AppDiagnostic.Logging/obj/Debug/net472/AppDiagnostic.Logging.dll b/AppDiagnostic.Logging/obj/Debug/net472/AppDiagnostic.Logging.dll index fa3b3ef1c..178529b66 100644 Binary files a/AppDiagnostic.Logging/obj/Debug/net472/AppDiagnostic.Logging.dll and b/AppDiagnostic.Logging/obj/Debug/net472/AppDiagnostic.Logging.dll differ diff --git a/AppDiagnostic.Logging/obj/Debug/net472/AppDiagnostic.Logging.pdb b/AppDiagnostic.Logging/obj/Debug/net472/AppDiagnostic.Logging.pdb index c8da8e1d1..5325f29ac 100644 Binary files a/AppDiagnostic.Logging/obj/Debug/net472/AppDiagnostic.Logging.pdb and b/AppDiagnostic.Logging/obj/Debug/net472/AppDiagnostic.Logging.pdb differ diff --git a/AppDiagnostic.Logging/obj/Release/net472/AppDiagnostic.Logging.AssemblyInfo.cs b/AppDiagnostic.Logging/obj/Release/net472/AppDiagnostic.Logging.AssemblyInfo.cs index a53fb10a6..b14d8957d 100644 --- a/AppDiagnostic.Logging/obj/Release/net472/AppDiagnostic.Logging.AssemblyInfo.cs +++ b/AppDiagnostic.Logging/obj/Release/net472/AppDiagnostic.Logging.AssemblyInfo.cs @@ -14,7 +14,7 @@ using System.Reflection; [assembly: System.Reflection.AssemblyCompanyAttribute("AppDiagnostic.Logging")] [assembly: System.Reflection.AssemblyConfigurationAttribute("Release")] [assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")] -[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+086bb55595ffea5be7adb163ca4c6489903ed67c")] +[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+73c8fecdf26ee704bb58f3b6ad4a3379d7cfbe4b")] [assembly: System.Reflection.AssemblyProductAttribute("AppDiagnostic.Logging")] [assembly: System.Reflection.AssemblyTitleAttribute("AppDiagnostic.Logging")] [assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")] diff --git a/AppDiagnostic.Logging/obj/Release/net472/AppDiagnostic.Logging.AssemblyInfoInputs.cache b/AppDiagnostic.Logging/obj/Release/net472/AppDiagnostic.Logging.AssemblyInfoInputs.cache index baac57ee0..63fd9f04e 100644 --- a/AppDiagnostic.Logging/obj/Release/net472/AppDiagnostic.Logging.AssemblyInfoInputs.cache +++ b/AppDiagnostic.Logging/obj/Release/net472/AppDiagnostic.Logging.AssemblyInfoInputs.cache @@ -1 +1 @@ -aad509aee7434678bd40a99ea120dafb7aa8b4f050f239aae2fbef41167a7201 +e0875c8a97ddb41066398730e4c9b2ab4eeacaec1b71f3d88c7d2a711f88bfc3 diff --git a/AppDiagnostic.Logging/obj/Release/net472/AppDiagnostic.Logging.csproj.AssemblyReference.cache b/AppDiagnostic.Logging/obj/Release/net472/AppDiagnostic.Logging.csproj.AssemblyReference.cache index 883e6d9b0..bdcce23b0 100644 Binary files a/AppDiagnostic.Logging/obj/Release/net472/AppDiagnostic.Logging.csproj.AssemblyReference.cache and b/AppDiagnostic.Logging/obj/Release/net472/AppDiagnostic.Logging.csproj.AssemblyReference.cache differ diff --git a/AppDiagnostic.Logging/obj/Release/net472/AppDiagnostic.Logging.csproj.CoreCompileInputs.cache b/AppDiagnostic.Logging/obj/Release/net472/AppDiagnostic.Logging.csproj.CoreCompileInputs.cache index c31c2aa80..4fd542aed 100644 --- a/AppDiagnostic.Logging/obj/Release/net472/AppDiagnostic.Logging.csproj.CoreCompileInputs.cache +++ b/AppDiagnostic.Logging/obj/Release/net472/AppDiagnostic.Logging.csproj.CoreCompileInputs.cache @@ -1 +1 @@ -53dfa6175dfb762da95c667a45dfe918166697a8741b3f7c14601d1f62b1886d +a53d59482cad49b656138b1af5cf3e55edf2108969aedc574c362be6c671436b diff --git a/AppDiagnostic.Logging/obj/Release/net472/AppDiagnostic.Logging.dll b/AppDiagnostic.Logging/obj/Release/net472/AppDiagnostic.Logging.dll index 92ba99691..42b3c07eb 100644 Binary files a/AppDiagnostic.Logging/obj/Release/net472/AppDiagnostic.Logging.dll and b/AppDiagnostic.Logging/obj/Release/net472/AppDiagnostic.Logging.dll differ diff --git a/AppDiagnostic.Logging/obj/Release/net472/AppDiagnostic.Logging.pdb b/AppDiagnostic.Logging/obj/Release/net472/AppDiagnostic.Logging.pdb index 20f7774dc..84738e995 100644 Binary files a/AppDiagnostic.Logging/obj/Release/net472/AppDiagnostic.Logging.pdb and b/AppDiagnostic.Logging/obj/Release/net472/AppDiagnostic.Logging.pdb differ diff --git a/GenesisCordonelInterface/API/InterfaceGCIToLaatzen.cs b/GenesisCordonelInterface/API/InterfaceGCIToLaatzen.cs index b4bca85a0..ca2c7d263 100644 --- a/GenesisCordonelInterface/API/InterfaceGCIToLaatzen.cs +++ b/GenesisCordonelInterface/API/InterfaceGCIToLaatzen.cs @@ -282,7 +282,7 @@ namespace GenesisCordonelInterface.API PortConfig? str, CancellationToken token = default) { - return GetWorker(slot).RunAsync(() => InitSlot(slot, cfg, pwd, req, str), token); + return GetWorker(slot).RunAsync(() => InitSlot(slot, cfg, pwd, req, str), token, nameof(InitSlot)); } public PublicModels.GciInitSlotResult InitSlot( @@ -334,7 +334,7 @@ namespace GenesisCordonelInterface.API PortConfig? str, CancellationToken token = default) { - return GetWorker(slot).RunAsync(() => UpdateSlot(slot, cfg, pwd, req, str), token); + return GetWorker(slot).RunAsync(() => UpdateSlot(slot, cfg, pwd, req, str), token, nameof(UpdateSlot)); } public PublicModels.GciInitSlotResult UpdateSlot( @@ -491,7 +491,7 @@ namespace GenesisCordonelInterface.API int slot, CancellationToken token = default) { - return GetWorker(slot).RunAsync(() => GetOneMeterInfo(slot), token); + return GetWorker(slot).RunAsync(() => GetOneMeterInfo(slot), token, nameof(GetOneMeterInfo)); } public PublicModels.GciSlotInfo GetOneMeterInfo(int slot) @@ -702,7 +702,7 @@ namespace GenesisCordonelInterface.API int slot, CancellationToken token = default(CancellationToken)) { - return GetWorker(slot).RunAsync(() => DetectStreamingPort(slot), token); + return GetWorker(slot).RunAsync(() => DetectStreamingPort(slot), token, nameof(DetectStreamingPort)); } public PortDetectionResult DetectStreamingPort(int slot) @@ -757,7 +757,7 @@ namespace GenesisCordonelInterface.API int slot, CancellationToken token = default(CancellationToken)) { - return GetWorker(slot).RunAsync(() => DetectRequestPort(slot), token); + return GetWorker(slot).RunAsync(() => DetectRequestPort(slot), token, nameof(DetectRequestPort)); } public PortDetectionResult DetectRequestPort(int slot) @@ -807,7 +807,7 @@ namespace GenesisCordonelInterface.API #region ================================== LOGIN ================================== public Task LoginOneSlotAsync(int slot, CancellationToken token = default) { - return GetWorker(slot).RunAsync(() => LoginOneSlot(slot), token); + return GetWorker(slot).RunAsync(() => LoginOneSlot(slot), token, nameof(LoginOneSlot)); } public PublicModels.GciLoginResult LoginOneSlot(int slot) @@ -881,7 +881,7 @@ namespace GenesisCordonelInterface.API public Task ConnectOneSlotAsync(int slot, CancellationToken token = default) { - return GetWorker(slot).RunAsync(() => ConnectOneSlot(slot), token); + return GetWorker(slot).RunAsync(() => ConnectOneSlot(slot), token, nameof(ConnectOneSlot)); } public PublicModels.GciConnectResult ConnectOneSlot(int slot) @@ -972,7 +972,7 @@ namespace GenesisCordonelInterface.API int slot, CancellationToken token = default) { - return GetWorker(slot).RunAsync(() => Disconnect(slot), token); + return GetWorker(slot).RunAsync(() => Disconnect(slot), token, nameof(Disconnect)); } public PublicModels.GciDisconnectResult Disconnect(int slot) @@ -1059,7 +1059,7 @@ namespace GenesisCordonelInterface.API int slot, CancellationToken token = default(CancellationToken)) { - return GetWorker(slot).RunAsync(() => GetPcbId(slot), token, "GetPcbId"); + return GetWorker(slot).RunAsync(() => GetPcbId(slot), token, nameof(GetPcbId)); } public PublicModels.GciGetPcbIdResult GetPcbId(int slot) @@ -1112,7 +1112,7 @@ namespace GenesisCordonelInterface.API public Task ReadRegisterAsync(int slot, string name, CancellationToken token = default) { - return GetWorker(slot).RunAsync(() => ReadRegister(slot, name), token); + return GetWorker(slot).RunAsync(() => ReadRegister(slot, name), token, nameof(ReadRegister)); } public RegisterReadResult ReadRegister(int slot, string name) @@ -1166,7 +1166,7 @@ namespace GenesisCordonelInterface.API bool refreshSystemState = false, CancellationToken token = default) { - return GetWorker(slot).RunAsync(() => WriteRegister(slot, registerName, value, storeToDevice, refreshSystemState), token); + return GetWorker(slot).RunAsync(() => WriteRegister(slot, registerName, value, storeToDevice, refreshSystemState), token, nameof(WriteRegister)); } public RegisterWriteResult WriteRegister( @@ -1279,7 +1279,7 @@ namespace GenesisCordonelInterface.API { return GetWorker(slot).RunAsync(() => SetMeterPassword(slot, password), token, - "SetMeterPassword"); + nameof(SetMeterPassword)); } public PublicModels.GciSetPasswordResult SetMeterPassword( @@ -1826,7 +1826,8 @@ namespace GenesisCordonelInterface.API { return GetWorker(slot).RunAsync( () => PreAdjustment_Preparation(slot), - token); + token, + nameof(PreAdjustment_Preparation)); } public PreAdjustmentProcessResult PreAdjustment_PreparationDirect() @@ -1925,7 +1926,8 @@ namespace GenesisCordonelInterface.API { return GetWorker(slot).RunAsync( () => PreAdjustment_AmplitudeTest(slot), - token); + token, + nameof(PreAdjustment_AmplitudeTest)); } public PreAdjustmentProcessResult PreAdjustment_AmplitudeTestDirect() @@ -2015,7 +2017,8 @@ namespace GenesisCordonelInterface.API { return GetWorker(slot).RunAsync( () => PreAdjustment_TemperatureCalibration(slot), - token); + token, + nameof(PreAdjustment_TemperatureCalibration)); } public PreAdjustmentProcessResult PreAdjustment_TemperatureCalibrationDirect() @@ -2112,7 +2115,8 @@ namespace GenesisCordonelInterface.API { return GetWorker(slot).RunAsync( () => PreAdjustment_OffsetTest(slot), - token); + token, + nameof(PreAdjustment_OffsetTest)); } public PreAdjustmentProcessResult PreAdjustment_OffsetTestDirect() @@ -2207,7 +2211,8 @@ namespace GenesisCordonelInterface.API { return GetWorker(slot).RunAsync( () => PreAdjustment_Completion(slot), - token); + token, + nameof(PreAdjustment_Completion)); } public PreAdjustmentProcessResult PreAdjustment_CompletionDirect() @@ -2317,4 +2322,4 @@ namespace GenesisCordonelInterface.API } #endregion } -} \ No newline at end of file +} diff --git a/GenesisCordonelInterface/Core/Threading/ApiWorker/ApiWorker.cs b/GenesisCordonelInterface/Core/Threading/ApiWorker/ApiWorker.cs index e154e4112..759ba54c8 100644 --- a/GenesisCordonelInterface/Core/Threading/ApiWorker/ApiWorker.cs +++ b/GenesisCordonelInterface/Core/Threading/ApiWorker/ApiWorker.cs @@ -174,7 +174,8 @@ namespace GenesisCordonelInterface.Core.Threading public sealed class ApiWorker : IDisposable { - private static readonly NLog.ILogger Logger = NLog.LogManager.GetLogger("GenesisCordonelInterface-threading"); + private static readonly NLog.ILogger Logger = NLog.LogManager.GetLogger("GenesisCordonelInterface.SlotWorker"); + private static long nextRequestId; /// /// Thread-safe FIFO queue holding work items. /// @@ -232,6 +233,12 @@ namespace GenesisCordonelInterface.Core.Threading }; thread.Start(); + + Logger.Info( + "[SLOT-WORKER] CREATED Worker={0}, WorkerThread={1}, CallerThread={2}", + Name, + thread.ManagedThreadId, + Thread.CurrentThread.ManagedThreadId); } /// @@ -251,31 +258,93 @@ namespace GenesisCordonelInterface.Core.Threading var tcs = new TaskCompletionSource( TaskCreationOptions.RunContinuationsAsynchronously); + long requestId = Interlocked.Increment(ref nextRequestId); + string operation = string.IsNullOrWhiteSpace(operationName) ? action.Method.Name : operationName; + int callerThreadId = Thread.CurrentThread.ManagedThreadId; + Stopwatch queueWait = Stopwatch.StartNew(); + try { - Debug.WriteLine($"ENQUEUE {operationName} slot worker={Name} time={DateTime.Now:HH:mm:ss.fff}"); + Logger.Debug( + "[SLOT-REQUEST] ENQUEUE RequestId={0}, Worker={1}, Operation={2}, CallerThread={3}, QueueLengthBefore={4}", + requestId, + Name, + operation, + callerThreadId, + QueueLength); + queue.Add(() => { if (token.IsCancellationRequested) { + queueWait.Stop(); + LastActivity = DateTime.Now; + + Logger.Warn( + "[SLOT-REQUEST] CANCELLED_BEFORE_START RequestId={0}, Worker={1}, Operation={2}, WorkerThread={3}, QueueWaitMs={4}, QueueLength={5}", + requestId, + Name, + operation, + Thread.CurrentThread.ManagedThreadId, + queueWait.ElapsedMilliseconds, + QueueLength); + tcs.TrySetCanceled(); return; } + Stopwatch execution = Stopwatch.StartNew(); + try { IsBusy = true; - CurrentOperation = operationName ?? action.Method.Name; + CurrentOperation = operation; LastActivity = DateTime.Now; LastError = null; + queueWait.Stop(); + + Logger.Debug( + "[SLOT-REQUEST] START RequestId={0}, Worker={1}, Operation={2}, WorkerThread={3}, CallerThread={4}, QueueWaitMs={5}, QueueLength={6}", + requestId, + Name, + operation, + Thread.CurrentThread.ManagedThreadId, + callerThreadId, + queueWait.ElapsedMilliseconds, + QueueLength); + var result = action(); tcs.TrySetResult(result); + + execution.Stop(); + + Logger.Debug( + "[SLOT-REQUEST] COMPLETE RequestId={0}, Worker={1}, Operation={2}, WorkerThread={3}, DurationMs={4}, QueueLength={5}", + requestId, + Name, + operation, + Thread.CurrentThread.ManagedThreadId, + execution.ElapsedMilliseconds, + QueueLength); } catch (Exception ex) { + execution.Stop(); LastError = ex.Message; + + Logger.Error( + ex, + "[SLOT-REQUEST] FAILED RequestId={0}, Worker={1}, Operation={2}, WorkerThread={3}, DurationMs={4}, QueueLength={5}, Error={6}", + requestId, + Name, + operation, + Thread.CurrentThread.ManagedThreadId, + execution.ElapsedMilliseconds, + QueueLength, + ex.Message); + tcs.TrySetException(ex); } finally @@ -286,13 +355,47 @@ namespace GenesisCordonelInterface.Core.Threading } }, token); } + catch (OperationCanceledException) + { + queueWait.Stop(); + + Logger.Warn( + "[SLOT-REQUEST] ENQUEUE_CANCELLED RequestId={0}, Worker={1}, Operation={2}, CallerThread={3}, QueueWaitMs={4}", + requestId, + Name, + operation, + callerThreadId, + queueWait.ElapsedMilliseconds); + + tcs.TrySetCanceled(); + } catch (ObjectDisposedException ex) { + queueWait.Stop(); + + Logger.Error( + ex, + "[SLOT-REQUEST] ENQUEUE_FAILED RequestId={0}, Worker={1}, Operation={2}, Reason=WorkerDisposed", + requestId, + Name, + operation); + tcs.TrySetException(ex); } catch (InvalidOperationException ex) { - tcs.TrySetException(new ObjectDisposedException(nameof(ApiWorker), ex)); + queueWait.Stop(); + + var disposedException = new ObjectDisposedException(nameof(ApiWorker), ex); + + Logger.Error( + disposedException, + "[SLOT-REQUEST] ENQUEUE_FAILED RequestId={0}, Worker={1}, Operation={2}, Reason=QueueCompleted", + requestId, + Name, + operation); + + tcs.TrySetException(disposedException); } return tcs.Task; @@ -327,6 +430,11 @@ namespace GenesisCordonelInterface.Core.Threading /// private void WorkerLoop() { + Logger.Info( + "[SLOT-WORKER] THREAD_STARTED Worker={0}, WorkerThread={1}", + Name, + Thread.CurrentThread.ManagedThreadId); + try { foreach (var item in queue.GetConsumingEnumerable()) @@ -339,7 +447,26 @@ namespace GenesisCordonelInterface.Core.Threading } catch (ObjectDisposedException) { - // worker is shutting down + Logger.Debug( + "[SLOT-WORKER] QUEUE_DISPOSED Worker={0}, WorkerThread={1}", + Name, + Thread.CurrentThread.ManagedThreadId); + } + catch (Exception ex) + { + Logger.Error( + ex, + "[SLOT-WORKER] THREAD_FAILED Worker={0}, WorkerThread={1}, Error={2}", + Name, + Thread.CurrentThread.ManagedThreadId, + ex.Message); + } + finally + { + Logger.Info( + "[SLOT-WORKER] THREAD_STOPPED Worker={0}, WorkerThread={1}", + Name, + Thread.CurrentThread.ManagedThreadId); } } @@ -351,14 +478,41 @@ namespace GenesisCordonelInterface.Core.Threading if (disposed) return; + Logger.Info( + "[SLOT-WORKER] DISPOSE_BEGIN Worker={0}, CallerThread={1}, WorkerThread={2}, IsBusy={3}, CurrentOperation={4}, QueueLength={5}", + Name, + Thread.CurrentThread.ManagedThreadId, + thread.ManagedThreadId, + IsBusy, + CurrentOperation ?? "", + QueueLength); + disposed = true; queue.CompleteAdding(); if (Thread.CurrentThread != thread && thread.IsAlive) - thread.Join(1000); + { + bool stopped = thread.Join(1000); + if (!stopped) + { + Logger.Warn( + "[SLOT-WORKER] DISPOSE_WAIT_TIMEOUT Worker={0}, WorkerThread={1}, CurrentOperation={2}, QueueLength={3}", + Name, + thread.ManagedThreadId, + CurrentOperation ?? "", + QueueLength); + } + } queue.Dispose(); + + Logger.Info( + "[SLOT-WORKER] DISPOSE_END Worker={0}, CallerThread={1}, WorkerThread={2}, ThreadAlive={3}", + Name, + Thread.CurrentThread.ManagedThreadId, + thread.ManagedThreadId, + thread.IsAlive); } } -} \ No newline at end of file +} diff --git a/TBF/Rig/TestMethods/GenesisCommunication/GenesisCommunicationSeq.cs b/TBF/Rig/TestMethods/GenesisCommunication/GenesisCommunicationSeq.cs index 100b8ddf3..a4c12f250 100644 --- a/TBF/Rig/TestMethods/GenesisCommunication/GenesisCommunicationSeq.cs +++ b/TBF/Rig/TestMethods/GenesisCommunication/GenesisCommunicationSeq.cs @@ -33,6 +33,7 @@ namespace TBF.Rig.TestMethods.GenesisCommunication public class GenesisCommunicationSeq : SequenceBase { private static readonly ILog log = LogManager.GetLogger(typeof(GenesisCommunicationSeq)); + private static readonly NLog.ILogger preadjustmentLogger = NLog.LogManager.GetLogger("GenesisCordonelInterface.GenesisCommunication.Preadjustment"); public const string Q2correctedFromCmd = "Q2 corrected from "; public const string StrictQ2ErrorCheckStr = "Strict Q2 error check "; @@ -50,6 +51,7 @@ namespace TBF.Rig.TestMethods.GenesisCommunication System.Windows.Forms.Form modelessDlg; + private GenesisCommunicationDiagnosticsForm preadjustmentDiagnosticsForm; /// delegate void iPerlCommFormDlgt(GenesisCommunicationSeq myRef, TestMethod method, Test test, iPerlCommunicationParams testParams); /// @@ -69,6 +71,40 @@ 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)); + } + /// /// Flying start mass collection method sequence @@ -458,24 +494,74 @@ namespace TBF.Rig.TestMethods.GenesisCommunication Bridge.OnTestProgress(this, new TestProgressEventArgs(test, Progress.JustStarted)); Bridge.OnActivity(this, testParams.Activity); + preadjustmentLogger.Info( + "[PREADJUSTMENT] START Test={0}, Part={1}, Activity={2}, MeterSize={3}, Temperature={4}, CallerThread={5}", + test.Name, + test.Part, + testParams.Activity, + testParams.MeterSize, + testParams.Temperature, + Thread.CurrentThread.ManagedThreadId); + try { readers = GetPreadjustmentReaders(test); GciBridgeType bridge = GetCommonGciBridge(readers); + + preadjustmentLogger.Info( + "[PREADJUSTMENT] CONTEXT Test={0}, Activity={1}, Bridge={2}, Slots={3}, ReaderCount={4}", + test.Name, + testParams.Activity, + bridge.Name, + string.Join(",", readers.Select(item => item.Value.GetSlotNr)), + readers.Count); + + ShowPreadjustmentDiagnostics(bridge, testParams.Activity); success = ExecutePreadjustmentActivity(bridge, readers, testParams, out response); } catch (Exception ex) { response = ex.Message; log.Error(string.Format("{0} failed.", testParams.Activity), ex); + + preadjustmentLogger.Error( + ex, + "[PREADJUSTMENT] FAILED Test={0}, Part={1}, Activity={2}, DurationMs={3}, Error={4}", + test.Name, + test.Part, + testParams.Activity, + (long)(DateTime.Now - startTime).TotalMilliseconds, + ex.Message); + } + finally + { + HidePreadjustmentDiagnostics(); } UpdatePreadjustmentResult(test, method, readers, success, startTime); if (success) + { log.InfoFormat("{0} finished successfully. {1}", testParams.Activity, response); + preadjustmentLogger.Info( + "[PREADJUSTMENT] COMPLETE Test={0}, Part={1}, Activity={2}, Success=True, DurationMs={3}, Response={4}", + test.Name, + test.Part, + testParams.Activity, + (long)(DateTime.Now - startTime).TotalMilliseconds, + response); + } else + { log.ErrorFormat("{0} failed. {1}", testParams.Activity, response); + preadjustmentLogger.Error( + "[PREADJUSTMENT] COMPLETE Test={0}, Part={1}, Activity={2}, Success=False, DurationMs={3}, Response={4}", + test.Name, + test.Part, + testParams.Activity, + (long)(DateTime.Now - startTime).TotalMilliseconds, + response); + } Bridge.OnActivity(this, string.Format("{0}: {1}", testParams.Activity, response)); Bridge.OnTestProgress(this, new TestProgressEventArgs(test, Progress.Completed)); @@ -537,10 +623,17 @@ namespace TBF.Rig.TestMethods.GenesisCommunication private static bool ExecutePreadjustmentActivity(GciBridgeType bridge, IList> readers, iPerlCommunicationParams testParams, out string response) { + preadjustmentLogger.Debug( + "[PREADJUSTMENT] DISPATCH Activity={0}, Bridge={1}, Slots={2}, Thread={3}", + testParams.Activity, + bridge.Name, + string.Join(",", readers.Select(item => item.Value.GetSlotNr)), + Thread.CurrentThread.ManagedThreadId); + if (string.Equals(testParams.Activity, PreadjustmentInitializationStr, StringComparison.OrdinalIgnoreCase)) { MeterSize meterSize; - if (!Enum.TryParse(testParams.MeterSize, true, out meterSize) || meterSize == MeterSize.NA) + if (!Enum.TryParse(testParams.MeterSize, true, out meterSize) || meterSize.ToString().EndsWith("MAX", StringComparison.OrdinalIgnoreCase)) throw new InvalidOperationException(string.Format("Meter size '{0}' is not valid.", testParams.MeterSize)); var progress = new ProcessProgress @@ -567,6 +660,15 @@ namespace TBF.Rig.TestMethods.GenesisCommunication PublicModels.PreAdjustmentInitializationResult result = bridge.Preadjustment_Initialization(progress, meterControls); response = result.ToString(); + + preadjustmentLogger.Debug( + "[PREADJUSTMENT] INITIALIZATION_RESULT Success={0}, MeterSize={1}, NumberOfPaths={2}, MeterCount={3}, Response={4}", + result.Success, + meterSize, + progress.Setting.NumberOfPaths, + meterControls.Count, + response); + return result.Success; } @@ -575,6 +677,13 @@ namespace TBF.Rig.TestMethods.GenesisCommunication var selectedSlots = readers.Select(item => new GciPublicModels.MeterBatchDebugStatus { Slot = item.Value.GetSlotNr, Selected = true }).ToList(); PublicModels.PreadjustmentDetectResult result = bridge.PreAdjustment_DetectDirect(selectedSlots, CancellationToken.None); response = result.ToString(); + + preadjustmentLogger.Debug( + "[PREADJUSTMENT] DETECT_RESULT Success={0}, Slots={1}, Response={2}", + result.Success, + string.Join(",", selectedSlots.Select(item => item.Slot)), + response); + return result.Success; } @@ -583,6 +692,12 @@ namespace TBF.Rig.TestMethods.GenesisCommunication // Keep temperature delivery as an explicit sibling GCI API activity. A procedure can run it simultaneously with temperature calibration. bool pushed = bridge.PreAdjustment_PushTemperature(testParams.Temperature); response = pushed ? string.Format("Temperature {0} °C was accepted.", testParams.Temperature) : "GCI preadjustment was not initialized; temperature was not accepted."; + + preadjustmentLogger.Debug( + "[PREADJUSTMENT] TEMPERATURE_PUSH Result={0}, Temperature={1}", + pushed, + testParams.Temperature); + return pushed; } @@ -601,6 +716,15 @@ namespace TBF.Rig.TestMethods.GenesisCommunication throw new InvalidOperationException(string.Format("Unsupported preadjustment activity '{0}'.", testParams.Activity)); response = processResult.ToString(); + + preadjustmentLogger.Debug( + "[PREADJUSTMENT] PROCESS_RESULT Activity={0}, Process={1}, Slot={2}, Success={3}, Error={4}", + testParams.Activity, + processResult.ProcessName, + processResult.Slot, + processResult.Success, + processResult.ErrorMessage ?? ""); + return processResult.Success; } @@ -625,6 +749,14 @@ namespace TBF.Rig.TestMethods.GenesisCommunication meterResult.WaterMeter.SerialNr = item.Value.SerialNr; meterResult.Passed = success; meterResult.TestDone = true; + + preadjustmentLogger.Debug( + "[PREADJUSTMENT] RESULT_UPDATE Test={0}, Part={1}, MeterPosition={2}, Slot={3}, Passed={4}", + test.Name, + test.Part, + item.Key, + item.Value.GetSlotNr, + success); } } diff --git a/TBF/Rig/TestMethods/GenesisCommunication/UI/GenesisCommunicationDiagnosticsForm.Designer.cs b/TBF/Rig/TestMethods/GenesisCommunication/UI/GenesisCommunicationDiagnosticsForm.Designer.cs new file mode 100644 index 000000000..f942bf50e --- /dev/null +++ b/TBF/Rig/TestMethods/GenesisCommunication/UI/GenesisCommunicationDiagnosticsForm.Designer.cs @@ -0,0 +1,346 @@ +namespace TBF.Rig.TestMethods.GenesisCommunication +{ + partial class GenesisCommunicationDiagnosticsForm + { + private System.ComponentModel.IContainer components = null; + + protected override void Dispose(bool disposing) + { + if (disposing && (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.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.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.refreshTimer.Interval = 250; + this.refreshTimer.Tick += new System.EventHandler(this.refreshTimer_Tick); + // + // GenesisCommunicationDiagnosticsForm + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + 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.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.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; + } +} diff --git a/TBF/Rig/TestMethods/GenesisCommunication/UI/GenesisCommunicationDiagnosticsForm.cs b/TBF/Rig/TestMethods/GenesisCommunication/UI/GenesisCommunicationDiagnosticsForm.cs new file mode 100644 index 000000000..f19f7471c --- /dev/null +++ b/TBF/Rig/TestMethods/GenesisCommunication/UI/GenesisCommunicationDiagnosticsForm.cs @@ -0,0 +1,78 @@ +using System; +using System.Collections.Generic; +using System.Windows.Forms; +using GciBridgeType = TBF.Rig.BridgeComponents.GciBridge.GciBridge; +using GciPublicModels = GenesisCordonelInterface.API.PublicModels; + +namespace TBF.Rig.TestMethods.GenesisCommunication +{ + /// + /// Displays live GCI slot and worker information while a GenesisCommunication + /// preadjustment activity is running. + /// + public partial class GenesisCommunicationDiagnosticsForm : Form + { + private readonly GciBridgeType bridge; + private readonly string activity; + + public GenesisCommunicationDiagnosticsForm(GciBridgeType bridge, string activity) + { + if (bridge == null) + throw new ArgumentNullException("bridge"); + + this.bridge = bridge; + this.activity = activity ?? string.Empty; + + InitializeComponent(); + activityToolStripLabel.Text = "Running activity: " + this.activity; + } + + private void GenesisCommunicationDiagnosticsForm_Load(object sender, EventArgs e) + { + RefreshDiagnostics(); + refreshTimer.Start(); + } + + private void GenesisCommunicationDiagnosticsForm_FormClosed(object sender, FormClosedEventArgs e) + { + 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 + { + var api = bridge.gciExternalInterface; + List slotStatuses = api == null + ? new List() + : api.GetMeterBatchDebugStatuses() ?? new List(); + List workerStatuses = api == null + ? new List() + : api.GetWorkerDebugStatuses() ?? new List(); + + 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; + } + } + } +} diff --git a/TBF/Rig/TestMethods/GenesisCommunication/UI/GenesisCommunicationDiagnosticsForm.resx b/TBF/Rig/TestMethods/GenesisCommunication/UI/GenesisCommunicationDiagnosticsForm.resx new file mode 100644 index 000000000..3ac5e42c8 --- /dev/null +++ b/TBF/Rig/TestMethods/GenesisCommunication/UI/GenesisCommunicationDiagnosticsForm.resx @@ -0,0 +1,61 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + diff --git a/TBF/TBF.csproj b/TBF/TBF.csproj index b9c766b6c..8d6909bba 100644 --- a/TBF/TBF.csproj +++ b/TBF/TBF.csproj @@ -2011,6 +2011,12 @@ TestMethodCfgCtrl.cs + + Form + + + GenesisCommunicationDiagnosticsForm.cs + Component @@ -4006,6 +4012,9 @@ TestMethodCfgCtrl.cs + + GenesisCommunicationDiagnosticsForm.cs + GrabImageCfgCtrl.cs @@ -4685,8 +4694,12 @@ Form - - + + GenesisCommunicationForm.cs + + + GenesisCommunicationForm.cs + diff --git a/TBF/UI/MainWnd.cs b/TBF/UI/MainWnd.cs index 70933832a..51427afb0 100644 --- a/TBF/UI/MainWnd.cs +++ b/TBF/UI/MainWnd.cs @@ -649,7 +649,7 @@ namespace TBF.UI } reloadProceduresButton.Enabled = procedureComboBox.Enabled = ((args.Flags & ButtonsEtc.ProcedureCmbBoxEn) != 0); - optoHeadsToolStripMenuItem.Enabled = ((args.Flags & ButtonsEtc.ProcedureCmbBoxEn) != 0); + optoHeadsToolStripMenuItem.Enabled = true;//((args.Flags & ButtonsEtc.ProcedureCmbBoxEn) != 0); if (procedureComboBox.Enabled) {