using System; using System.Drawing; using System.Windows.Forms; using System.Threading; using System.Diagnostics; using AR; using COMM; namespace Project.Dialog { public partial class fStateMachineDebug : Form { private System.Windows.Forms.Timer updateTimer; private TextBox txtDebugInfo; private Button btnRefresh; private Button btnForceRestart; public fStateMachineDebug() { InitializeComponent(); InitializeCustomComponents(); updateTimer = new System.Windows.Forms.Timer(); updateTimer.Interval = 500; // 0.5초마다 업데이트 updateTimer.Tick += UpdateTimer_Tick; updateTimer.Start(); } private void InitializeCustomComponents() { this.Text = "상태머신 디버그 모니터"; this.Size = new Size(800, 600); this.StartPosition = FormStartPosition.CenterScreen; this.FormBorderStyle = FormBorderStyle.Sizable; // TextBox 생성 txtDebugInfo = new TextBox { Multiline = true, ScrollBars = ScrollBars.Both, Dock = DockStyle.Fill, Font = new Font("Consolas", 9), ReadOnly = true, BackColor = Color.Black, ForeColor = Color.LimeGreen }; // 버튼 패널 var buttonPanel = new Panel { Dock = DockStyle.Bottom, Height = 50 }; btnRefresh = new Button { Text = "새로고침", Location = new Point(10, 10), Size = new Size(100, 30) }; btnRefresh.Click += (s, e) => UpdateDebugInfo(); btnForceRestart = new Button { Text = "상태머신 재시작", Location = new Point(120, 10), Size = new Size(120, 30), BackColor = Color.IndianRed }; btnForceRestart.Click += BtnForceRestart_Click; var btnBreakNow = new Button { Text = "즉시 중단", Location = new Point(250, 10), Size = new Size(100, 30), BackColor = Color.Orange }; btnBreakNow.Click += (s, ev) => { if (System.Diagnostics.Debugger.IsAttached) { System.Diagnostics.Debugger.Break(); } else { MessageBox.Show("디버거가 연결되지 않았습니다.", "알림"); } }; buttonPanel.Controls.Add(btnRefresh); buttonPanel.Controls.Add(btnForceRestart); buttonPanel.Controls.Add(btnBreakNow); this.Controls.Add(txtDebugInfo); this.Controls.Add(buttonPanel); } private void UpdateTimer_Tick(object sender, EventArgs e) { UpdateDebugInfo(); } private void UpdateDebugInfo() { try { var info = new System.Text.StringBuilder(); info.AppendLine("=== 상태머신 디버그 정보 ==="); info.AppendLine($"현재 시간: {DateTime.Now:yyyy-MM-dd HH:mm:ss.fff}"); info.AppendLine(); if (PUB.sm != null) { info.AppendLine($"상태머신 객체: 존재"); info.AppendLine($"IsThreadRun: {PUB.sm.IsThreadRun}"); info.AppendLine($"LoopCount: {PUB.sm.LoopCount}"); var lastLoopElapsed = (DateTime.Now - PUB.sm.LastLoopTime).TotalSeconds; var loopStatus = lastLoopElapsed < 1 ? "정상" : "경고!"; var loopColor = lastLoopElapsed < 1 ? "" : " <<<<<<"; info.AppendLine($"마지막 루프: {lastLoopElapsed:F2}초 전 [{loopStatus}]{loopColor}"); info.AppendLine($"현재 Step: {PUB.sm.Step}"); info.AppendLine($"현재 RunStep: {PUB.sm.RunStep}"); info.AppendLine($"Pause 상태: {PUB.sm.bPause}"); info.AppendLine($"WaitFirstRun: {PUB.sm.WaitFirstRun}"); // 스레드 정보 var smThread = GetStateMachineThread(); if (smThread != null) { info.AppendLine(); info.AppendLine($"스레드 이름: {smThread.Name ?? "N/A"}"); info.AppendLine($"스레드 ID: {smThread.ManagedThreadId}"); info.AppendLine($"스레드 상태: {smThread.ThreadState}"); info.AppendLine($"IsAlive: {smThread.IsAlive}"); info.AppendLine($"IsBackground: {smThread.IsBackground}"); } else { info.AppendLine(); info.AppendLine("경고: 상태머신 스레드를 찾을 수 없음!"); } } else { info.AppendLine("오류: 상태머신 객체가 NULL입니다!"); } info.AppendLine(); info.AppendLine("=== 변수 상태 ==="); info.AppendLine($"FLAG_AUTORUN: {VAR.BOOL[eVarBool.FLAG_AUTORUN]}"); info.AppendLine($"EMERGENCY: {VAR.BOOL[eVarBool.EMERGENCY]}"); info.AppendLine($"FLAG_SYNC: {VAR.BOOL[eVarBool.FLAG_SYNC]}"); info.AppendLine(); info.AppendLine("=== 하드웨어 연결 상태 ==="); info.AppendLine($"AGV: {(PUB.AGV?.IsOpen ?? false)} - {PUB.setting.Port_AGV}"); info.AppendLine($"XBE: {(PUB.XBE?.IsOpen ?? false)} - {PUB.setting.Port_XBE}"); info.AppendLine($"BMS: {(PUB.BMS?.IsOpen ?? false)} - {PUB.setting.Port_BAT}"); info.AppendLine(); info.AppendLine("=== 관리되는 스레드 목록 ==="); var currentProcess = Process.GetCurrentProcess(); info.AppendLine($"총 프로세스 스레드 수: {currentProcess.Threads.Count}"); // 모든 관리되는 스레드 정보 출력 foreach (ProcessThread thread in currentProcess.Threads) { var state = thread.ThreadState; var waitReason = thread.ThreadState == System.Diagnostics.ThreadState.Wait ? $", WaitReason: {thread.WaitReason}" : ""; info.AppendLine($" Thread {thread.Id}: State={state}, Priority={thread.PriorityLevel}{waitReason}"); } txtDebugInfo.Text = info.ToString(); } catch (Exception ex) { txtDebugInfo.Text = $"오류 발생: {ex.Message}\r\n{ex.StackTrace}"; } } private Thread GetStateMachineThread() { try { // Reflection을 사용하여 StateMachine의 private worker 필드 접근 var smType = PUB.sm.GetType(); var threadField = smType.GetField("worker", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance); if (threadField != null) { return threadField.GetValue(PUB.sm) as Thread; } } catch { } return null; } private void BtnForceRestart_Click(object sender, EventArgs e) { var result = MessageBox.Show( "상태머신을 강제로 재시작하시겠습니까?\n이 작업은 위험할 수 있습니다.", "경고", MessageBoxButtons.YesNo, MessageBoxIcon.Warning); if (result == DialogResult.Yes) { try { PUB.log.Add("StateMachine", "사용자가 강제 재시작 요청"); PUB.sm.Stop(); System.Threading.Thread.Sleep(1000); PUB.sm.Start(); PUB.log.Add("StateMachine", "강제 재시작 완료"); MessageBox.Show("상태머신이 재시작되었습니다.", "완료"); } catch (Exception ex) { MessageBox.Show($"재시작 실패: {ex.Message}", "오류"); PUB.log.AddE($"상태머신 재시작 실패: {ex.Message}"); } } } protected override void OnFormClosing(FormClosingEventArgs e) { updateTimer?.Stop(); updateTimer?.Dispose(); base.OnFormClosing(e); } } }