- sm_SPS 이벤트 핸들러에서 장치 연결 및 상태 전송을 비동기로 처리 - DeviceConnectionWorker 스레드로 장치 연결 분리 - SPS(1초), Running(2초) 타임아웃 보호 추가 - 상태머신 모니터링 디버그 창 추가 (fStateMachineDebug) - F11/F12 단축키로 스레드 덤프 및 디버그 브레이크 지원 - RaiseMessage 이벤트 비동기 처리로 로그 블로킹 방지
1203 lines
46 KiB
C#
1203 lines
46 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.ComponentModel;
|
|
using System.Data;
|
|
using System.Drawing;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using System.Windows.Forms;
|
|
using System.Runtime.InteropServices;
|
|
using COMM;
|
|
using System.CodeDom;
|
|
using AR;
|
|
using Project.StateMachine;
|
|
using System.Security.Cryptography.X509Certificates;
|
|
using AGVNavigationCore.Models;
|
|
using System.IO;
|
|
|
|
namespace Project
|
|
{
|
|
public partial class fMain : Form
|
|
{
|
|
double freeSpaceRate = 0.0;
|
|
|
|
//뷰어용화면
|
|
ViewForm.fAuto form_auto = null;
|
|
ViewForm.fManual form_manu = null;
|
|
ViewForm.fIO form_zlift = null;
|
|
ViewForm.fFlag form_flag = null;
|
|
ViewForm.fAgv form_agv = null;
|
|
ViewForm.fBms form_bms = null;
|
|
Dialog.fLog form_log = null;
|
|
|
|
bool remoteClose = false;
|
|
bool forceClose = false;
|
|
|
|
readonly usbdetect.DriveDetector usbdet;
|
|
public fMain()
|
|
{
|
|
InitializeComponent();
|
|
VAR.Init(128);
|
|
PUB.initCore();
|
|
this.KeyDown += (s1, e1) =>
|
|
{
|
|
if (e1.KeyCode == Keys.Escape) this.Close();
|
|
else if (e1.KeyCode == Keys.F1 && e1.Control && e1.Shift)
|
|
{
|
|
|
|
}
|
|
else if (e1.KeyCode == Keys.F5) btAutoRun.PerformClick();
|
|
else if (e1.KeyCode == Keys.F9) btAutoRun.PerformClick();
|
|
else if (e1.KeyCode == Keys.F11 && System.Diagnostics.Debugger.IsAttached)
|
|
{
|
|
// F11: 모든 스레드 상태 덤프
|
|
DumpAllThreadsState();
|
|
}
|
|
else if (e1.KeyCode == Keys.F12 && System.Diagnostics.Debugger.IsAttached)
|
|
{
|
|
// F12: 다음 sm_Running 호출시 디버거 중단
|
|
RequestDebugBreak = true;
|
|
var lastCall = DateTime.Now - lastSmRunningTime;
|
|
PUB.log.Add("DEBUG", $"F12 pressed - 마지막 sm_Running 호출: {lastCall.TotalSeconds:F1}초 전, IsThreadRun: {PUB.sm.IsThreadRun}");
|
|
System.Windows.Forms.MessageBox.Show(
|
|
$"다음 sm_Running 호출시 디버거가 중단됩니다.\n\n" +
|
|
$"마지막 호출: {lastCall.TotalSeconds:F1}초 전\n" +
|
|
$"IsThreadRun: {PUB.sm.IsThreadRun}\n" +
|
|
$"Current Step: {PUB.sm.Step}",
|
|
"디버그 모드",
|
|
System.Windows.Forms.MessageBoxButtons.OK,
|
|
System.Windows.Forms.MessageBoxIcon.Information);
|
|
}
|
|
|
|
if (DateTime.Now > PUB.LastInputTime) PUB.LastInputTime = DateTime.Now;
|
|
};
|
|
usbdet = new usbdetect.DriveDetector(this);
|
|
usbdet.DeviceArrived += Usbdet_DeviceArrived;
|
|
usbdet.DeviceRemoved += Usbdet_DeviceRemoved;
|
|
|
|
this.panTopMenu.MouseMove += LbTitle_MouseMove;
|
|
this.panTopMenu.MouseUp += LbTitle_MouseUp;
|
|
this.panTopMenu.MouseDown += LbTitle_MouseDown;
|
|
this.panTopMenu.DoubleClick += LbTitle_DoubleClick;
|
|
|
|
this.ctlPos1.ItemClick += CtlPos1_ItemClick;
|
|
this.MouseMove += (s1, e1) => { if (DateTime.Now > PUB.LastInputTime) PUB.LastInputTime = DateTime.Now; };
|
|
this.FormClosing += __Closing;
|
|
|
|
if (PUB.setting.FullScreen) this.WindowState = FormWindowState.Maximized;
|
|
|
|
}
|
|
|
|
protected override void WndProc(ref Message m)
|
|
{
|
|
base.WndProc(ref m);
|
|
if (usbdet != null)
|
|
{
|
|
usbdet.WndProc(ref m);
|
|
}
|
|
}
|
|
|
|
private void Usbdet_DeviceRemoved(object sender, usbdetect.DriveDetectorEventArgs e)
|
|
{
|
|
//throw new NotImplementedException();
|
|
Console.WriteLine(e.Drive);
|
|
}
|
|
|
|
private void Usbdet_DeviceArrived(object sender, usbdetect.DriveDetectorEventArgs e)
|
|
{
|
|
//throw new NotImplementedException();
|
|
using (var fUpdate = new Dialog.fUpdateForm(e.Drive))
|
|
if (fUpdate.ShowDialog() == DialogResult.Yes)
|
|
{
|
|
//종료한다
|
|
remoteClose = true;
|
|
this.Close();
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 상단 위치 표시기의 대상 위치값을 표시 합니다
|
|
/// </summary>
|
|
/// <param name="sender"></param>
|
|
/// <param name="e"></param>
|
|
private void Display_Position_TargetPosSet(object sender, EventArgs e)
|
|
{
|
|
//대상위치가 설정되었다x
|
|
this.ctlPos1.SetTargetPosition(PUB.Result.TargetPos);
|
|
this.ctlPos1.Invalidate();
|
|
}
|
|
|
|
|
|
private void __Closing(object sender, FormClosingEventArgs e)
|
|
{
|
|
// 장치 연결 쓰레드 종료
|
|
StopDeviceConnectionThread();
|
|
|
|
PUB.popup.needClose = true;
|
|
if (remoteClose == true)
|
|
{
|
|
PUB.log.Add("패치로 인해 프로그램을 종료 합니다");
|
|
PUB.sm.SetNewStep(eSMStep.IDLE);
|
|
//_Close_Start();
|
|
_STEP_CLOSING_START(PUB.sm.Step);
|
|
PUB.sm.Stop();
|
|
|
|
var patchfile = new System.IO.FileInfo(System.IO.Path.Combine(UTIL.CurrentPath, "SWPatch.exe"));
|
|
if (patchfile.Exists == false)
|
|
{
|
|
UTIL.MsgE("패치파일(" + patchfile.Name + ")이 없습니다.\n프로그램을 다시 실행해주세요", true);
|
|
}
|
|
else
|
|
{
|
|
UTIL.RunProcess(patchfile.FullName);
|
|
}
|
|
}
|
|
else if (forceClose == true)
|
|
{
|
|
PUB.log.Add("강제 종료");
|
|
PUB.sm.SetNewStep(eSMStep.IDLE);
|
|
//_Close_Start();
|
|
_STEP_CLOSING_START(PUB.sm.Step);
|
|
PUB.sm.Stop();
|
|
|
|
|
|
}
|
|
else
|
|
{
|
|
if (PUB.sm.Step == eSMStep.RUN)
|
|
{
|
|
UTIL.MsgE("동작 중에는 종료 할 수 없습니다.");
|
|
e.Cancel = true;
|
|
return;
|
|
}
|
|
if (PUB.sm.Step < eSMStep.CLOSING)
|
|
{
|
|
var rlt = UTIL.MsgQ("종료하시겠습니까");
|
|
if (rlt == System.Windows.Forms.DialogResult.Yes)
|
|
{
|
|
//비젼의 측정상태가 변경된 경우
|
|
PUB.sm.SetNewStep(eSMStep.CLOSING, true);
|
|
|
|
}
|
|
e.Cancel = true;
|
|
return;
|
|
//_Close_Start();
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
private Dictionary<string, int> FlagMap = new Dictionary<string, int>();
|
|
private void __Load(object sender, EventArgs e)
|
|
{
|
|
this.Text = Application.ProductName + " ver " + Application.ProductVersion;
|
|
//this.lbTitle.Text = this.Text;
|
|
PUB.init(); //public initialize
|
|
if (PUB.setting.FullScreen) this.WindowState = FormWindowState.Maximized;
|
|
// PUB.log.RaiseMsg += log_RaiseMsg;
|
|
this.Show();
|
|
|
|
PUB.Result.TargetPosSet += Display_Position_TargetPosSet;
|
|
|
|
this.ctlPos1.ClearData();
|
|
this.ctlPos1.Invalidate();
|
|
|
|
//lbDM1.Text = "";
|
|
//sbBatteryLv.Text = "";
|
|
btHome.Text = "홈";
|
|
btChargeA.Text = "자동충전";
|
|
VAR.STR[eVarString.SWVersion] = Application.ProductVersion;
|
|
Application.DoEvents();
|
|
|
|
//setting dio events
|
|
this.IOState.ItemClick += gridView2_ItemClick;
|
|
//PUB.flag.ValueChanged += Flag_ValueChagned;
|
|
VAR.BOOL.PropertyChanged += BOOL_PropertyChanged;
|
|
|
|
|
|
/////모터용 pLC
|
|
//PUB.PLC = new arDev.FakePLC();
|
|
//PUB.PLC.ValueChanged += PLC_DioChanged;
|
|
//PUB.PLC.FlagChanged += PLC_FlagChanged;
|
|
//PUB.PLC.Message += PLC_Message;
|
|
|
|
//지그비통신
|
|
PUB.XBE = new Device.Xbee();
|
|
PUB.XBE.MessageReceived += XBE_MessageReceived;
|
|
PUB.XBE.ProtocReceived += XBE_ProtocReceived;
|
|
|
|
//HWState.setTitle(1, 3, Pub.setting.Port_Xbee);
|
|
//HWState.setTitle(1, 0, Pub.setting.Address_RFID);
|
|
|
|
//AGV
|
|
PUB.AGV = new arDev.Narumi();
|
|
PUB.AGV.Message += AGV_Message;
|
|
PUB.AGV.DataReceive += AGV_DataReceive;
|
|
|
|
|
|
//배터리관리시스템
|
|
PUB.BMS = new arDev.BMS();
|
|
PUB.BMS.BMSDataReceive += Bms_BMSDataReceive;
|
|
PUB.BMS.BMSCellDataReceive += BMS_BMSCellDataReceive;
|
|
PUB.BMS.Message += Bms_Message;
|
|
PUB.BMS.ChargeDetect += BMS_ChargeDetect;
|
|
PUB.BMS.ScanInterval = PUB.setting.interval_bms;//
|
|
|
|
//디버그메세지 출력용 소켓
|
|
PUB.sock_debug = new Device.Socket();
|
|
PUB.sock_debug.GetMessage += socket_GetMessage;
|
|
PUB.sock_debug.RecvMessage += socket_RecvMessage;
|
|
PUB.sock_debug.SendMessage += socket_SendMessage;
|
|
|
|
//clear
|
|
Resultclear();
|
|
|
|
//충전이 시작되지 않도록 기본값을 넣는다
|
|
VAR.TIME[eVarTime.ChargeTry] = DateTime.Now;
|
|
VAR.TIME[eVarTime.ChargeSearch] = DateTime.Now;
|
|
|
|
PUB.sm.SetMsgOptOff(); //모든 메세지출력을 해제한다. (이벤트는 동작함)
|
|
|
|
PUB.log.Add("State Machine Start");
|
|
|
|
try
|
|
{
|
|
PUB.sm = new StateMachine.StateMachine();
|
|
PUB.log.Add("StateMachine", $"객체 생성 완료 - Type: {PUB.sm.GetType().FullName}");
|
|
|
|
// StateMachine 객체의 속성 확인
|
|
var smType = PUB.sm.GetType();
|
|
var properties = smType.GetProperties(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance);
|
|
PUB.log.Add("StateMachine", $"Public Properties: {properties.Length}개");
|
|
|
|
var methods = smType.GetMethods(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.DeclaredOnly);
|
|
PUB.log.Add("StateMachine", $"Public Methods: {methods.Length}개");
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
PUB.log.AddE($"StateMachine 객체 생성 실패: {ex.Message}");
|
|
PUB.log.AddE($"StackTrace: {ex.StackTrace}");
|
|
throw;
|
|
}
|
|
|
|
PUB.sm.StepChanged += sm_StepChanged;
|
|
PUB.log.Add("StateMachine", "StepChanged 이벤트 등록 완료");
|
|
|
|
PUB.sm.Message += sm_Message;
|
|
PUB.log.Add("StateMachine", "Message 이벤트 등록 완료");
|
|
|
|
PUB.sm.Running += sm_Running;
|
|
PUB.log.Add("StateMachine", "Running 이벤트 등록 완료");
|
|
|
|
PUB.sm.SPS += sm_SPS;
|
|
PUB.log.Add("StateMachine", "SPS 이벤트 등록 완료");
|
|
|
|
PUB.sm.Start();
|
|
PUB.log.Add("StateMachine", $"Start() 호출 완료 - IsThreadRun:{PUB.sm.IsThreadRun}");
|
|
|
|
// 스레드 시작 대기 (최대 3초)
|
|
for (int i = 0; i < 30; i++)
|
|
{
|
|
System.Threading.Thread.Sleep(100);
|
|
if (PUB.sm.IsThreadRun)
|
|
{
|
|
PUB.log.Add("StateMachine", $"스레드 시작 확인됨 ({i * 100}ms 소요)");
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!PUB.sm.IsThreadRun)
|
|
{
|
|
PUB.log.AddE( "경고: 3초 대기 후에도 스레드가 시작되지 않음!");
|
|
System.Windows.Forms.MessageBox.Show(
|
|
"상태머신 스레드가 시작되지 않았습니다.\n" +
|
|
"로그 파일을 확인하세요.",
|
|
"오류",
|
|
System.Windows.Forms.MessageBoxButtons.OK,
|
|
System.Windows.Forms.MessageBoxIcon.Error);
|
|
}
|
|
|
|
tmDisplay.Tick += tmDisplay_Tick;
|
|
tmDisplay.Start(); //start Display
|
|
PUB.log.Add("Display", "Display Timer 시작 완료");
|
|
|
|
this.btDebug.Visible = System.Diagnostics.Debugger.IsAttached || PUB.setting.UseDebugMode;
|
|
|
|
PUB.log.Add("Program Start");
|
|
|
|
|
|
//수량표시
|
|
PUB.counter.PropertyChanged += (s1, e1) => Update_Count();
|
|
Update_Count();
|
|
|
|
PUB.log.Add("프로그램 실행 기록 추가");
|
|
PUB.CheckNRegister3(Application.ProductName, "chi", Application.ProductVersion);
|
|
|
|
if (PUB.setting.StartLog)
|
|
MenuLog.PerformClick();
|
|
|
|
PUB.AddEEDB("프로그램 시작");
|
|
|
|
}
|
|
|
|
|
|
|
|
#region "Mouse Form Move"
|
|
|
|
private Boolean fMove = false;
|
|
private Point MDownPos;
|
|
|
|
private void LbTitle_DoubleClick(object sender, EventArgs e)
|
|
{
|
|
if (this.WindowState == FormWindowState.Maximized) this.WindowState = FormWindowState.Normal;
|
|
else this.WindowState = FormWindowState.Maximized;
|
|
}
|
|
private void LbTitle_MouseMove(object sender, MouseEventArgs e)
|
|
{
|
|
if (fMove)
|
|
{
|
|
Point offset = new Point(e.X - MDownPos.X, e.Y - MDownPos.Y);
|
|
this.Left += offset.X;
|
|
this.Top += offset.Y;
|
|
//offset = new Point(0, 0);
|
|
}
|
|
}
|
|
private void LbTitle_MouseUp(object sender, MouseEventArgs e)
|
|
{
|
|
fMove = false;
|
|
}
|
|
private void LbTitle_MouseDown(object sender, MouseEventArgs e)
|
|
{
|
|
MDownPos = new Point(e.X, e.Y);
|
|
fMove = true;
|
|
}
|
|
|
|
#endregion
|
|
void socket_SendMessage(object sender, Device.Socket.SocketMessageEventArgs e)
|
|
{
|
|
//핑로그가 꺼져있는 상황일때 핑로그는 로그를 기록하지 않는다. 181205
|
|
if (!PUB.setting.Log_Ping && e.Message.Type == Device.Socket.eType.REPLY && e.Message.SType == Device.Socket.eSType.STATUS)
|
|
{
|
|
return;
|
|
}
|
|
PUB.log.Add("WS << " + e.rawData);
|
|
}
|
|
|
|
void socket_RecvMessage(object sender, Device.Socket.SocketMessageEventArgs e)
|
|
{
|
|
if (e.Message.isError)
|
|
PUB.log.AddE("WS >> " + e.Message.ErrorMessage + ",RAW=" + e.rawData);
|
|
else
|
|
{
|
|
|
|
switch (e.Message.Type)
|
|
{
|
|
case Device.Socket.eType.REQUEST:
|
|
if (e.Message.SType == Device.Socket.eSType.STATUS)
|
|
{
|
|
var packet = PUB.sock_debug.makeReplyStatus(Device.Socket.eStatus.IDLE);
|
|
var rlt = PUB.sock_debug.Send(PUB.setting.Asset, Device.Socket.eType.REPLY, Device.Socket.eSType.STATUS, packet);
|
|
if (!rlt)
|
|
{
|
|
PUB.log.AddE("Status Reply Error");
|
|
}
|
|
else
|
|
{
|
|
if (PUB.setting.Log_Ping) PUB.log.AddI("Server Status Reply OK");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
PUB.log.Add("WS >> " + e.rawData);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void socket_GetMessage(object sender, Device.Socket.MesasgeEventArgs e)
|
|
{
|
|
if (e.isError) PUB.log.AddE("WS:" + e.Message);
|
|
else PUB.log.Add("WS:" + e.Message);
|
|
}
|
|
delegate void SelectModelHandler(string modelName);
|
|
void SelectModelM(string modelName)
|
|
{
|
|
if (this.InvokeRequired)
|
|
{
|
|
this.Invoke(new SelectModelHandler(SelectModelM), new object[] { modelName });
|
|
return;
|
|
}
|
|
}
|
|
|
|
void func_sw_start(bool Prompt = false)
|
|
{
|
|
if (VAR.BOOL[eVarBool.FLAG_AUTORUN] == false) //자동상태가 아니라면
|
|
{
|
|
PUB.AGV.AGVErrorReset();
|
|
if (Prompt)
|
|
{
|
|
if (UTIL.MsgQ("AGV상태를 자동으로 전환 할까요?") != DialogResult.Yes) return;
|
|
}
|
|
//충전상태확인
|
|
if (PUB.CheckManualChargeMode() == false) return;
|
|
PUB.popup.needClose = true;
|
|
PUB.sm.bPause = false;
|
|
PUB.sm.SetNewStep(eSMStep.RUN);
|
|
|
|
if (PUB.Result.CurrentPos == ePosition.NONE || PUB.Result.TargetPos == ePosition.NONE)
|
|
{
|
|
PUB.sm.SetNewRunStep(ERunStep.GOHOME);
|
|
}
|
|
PUB.Speak(Lang.자동전환);
|
|
}
|
|
else
|
|
{
|
|
PUB.AGV.AGVCharge(PUB.setting.ChargerID, false); //230425 수동전환하면 충전 해제한다
|
|
PUB.sm.SetNewStep(eSMStep.IDLE);
|
|
PUB.Speak(Lang.작업종료);
|
|
}
|
|
}
|
|
|
|
void Resultclear()
|
|
{
|
|
PUB.Result.Clear();
|
|
PUB.log.AddI("Clear Resultclear");
|
|
}
|
|
|
|
|
|
void CheckFreeSpace()
|
|
{
|
|
try
|
|
{
|
|
|
|
if (PUB.path.FullName.StartsWith("\\"))
|
|
{
|
|
SSInfo.setTitle(0, 1, "UNC Path Detected");
|
|
SSInfo.setValue(0, 1, 2);
|
|
}
|
|
else
|
|
{
|
|
double freeSpaceRate_ = PUB.GetFreeSpace();
|
|
this.freeSpaceRate = freeSpaceRate_;
|
|
SSInfo.setTitle(0, 1, "FREE(" + PUB.path.FullName.Substring(0, 1) + ") : " + freeSpaceRate.ToString("N2") + "%");
|
|
if (freeSpaceRate < PUB.setting.AutoDeleteThreshold)
|
|
{
|
|
VAR.BOOL[eVarBool.MINSPACE] = true;
|
|
SSInfo.setValue(0, 1, 2); //lbFreeSpace.ForeColor = Color.Tomato;
|
|
}
|
|
else
|
|
{
|
|
VAR.BOOL[eVarBool.MINSPACE] = false;
|
|
SSInfo.setValue(0, 1, 3);// lbFreeSpace.ForeColor = Color.White;
|
|
}
|
|
}
|
|
|
|
//Pub.log.Add("남은디스크공간확인:" + freeSpaceRate.ToString("N2") + "%"); 190129
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
SSInfo.setTitle(0, 1, "FREE SPACE : -ERROR-");
|
|
PUB.log.AddE("check free space : " + ex.Message);
|
|
}
|
|
}
|
|
|
|
|
|
private void CtlPos1_ItemClick(object sender, CtlPos.ItemClickEventArgs e)
|
|
{
|
|
if (VAR.BOOL[eVarBool.FLAG_CHARGEONM] == true)
|
|
{
|
|
UTIL.MsgE("수동 충전 상태이므로 진행 할 수 없습니다");
|
|
return;
|
|
}
|
|
if (VAR.BOOL[eVarBool.EMERGENCY] == true)
|
|
{
|
|
var dlgE = UTIL.MsgQ("비상정지 상태입니다.\n오류를 먼저 소거하고 실행 할까요?");
|
|
if (dlgE == DialogResult.Yes) PUB.AGV.AGVErrorReset();
|
|
else return;
|
|
}
|
|
//위치표시 컨트롤에서 아이템을 클릭했다
|
|
var dlg = new Dialog.fJobSelect();
|
|
PUB.log.Add("사용자 임의 위치 클릭 : " + e.Item.Title);
|
|
switch (e.Item.Position)
|
|
{
|
|
case ePosition.QA:
|
|
|
|
//아이템을 가지고 있었으니 하차를 해야한다
|
|
if (VAR.BOOL[eVarBool.ITEMON])
|
|
{
|
|
dlg.setMessage("작업 실행\n" +
|
|
"(QA) 위치로 하차를 진행 할까요?\n" +
|
|
"대상위치 : QA\n" +
|
|
"현재위치 : " + PUB.Result.CurrentPos.ToString());
|
|
if (dlg.ShowDialog() == DialogResult.Yes)
|
|
{
|
|
//아이템이 있으면 하차이고 없으면 상차이다
|
|
PUB.sm.ClearRunStep();
|
|
PUB.Result.TargetPos = ePosition.QA;
|
|
PUB.sm.SetNewRunStep(ERunStep.GODOWN);
|
|
PUB.sm.SetNewStep(eSMStep.RUN);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
dlg.setMessage("작업 실행\n" +
|
|
"(QA) 위치로 이동을 실행 할까요?\n" +
|
|
"대상위치 : QA\n" +
|
|
"현재위치 : " + PUB.Result.CurrentPos.ToString());
|
|
|
|
if (dlg.ShowDialog() == DialogResult.Yes)
|
|
{
|
|
|
|
//아이템이 있으면 하차이고 없으면 상차이다
|
|
PUB.sm.ClearRunStep();
|
|
PUB.Result.TargetPos = ePosition.QA;
|
|
PUB.sm.SetNewRunStep(ERunStep.GOHOME);
|
|
PUB.sm.SetNewStep(eSMStep.RUN);
|
|
}
|
|
}
|
|
|
|
break;
|
|
case ePosition.QC:
|
|
|
|
//아이템을 가지고 있었으니 하차를 해야한다
|
|
if (VAR.BOOL[eVarBool.ITEMON])
|
|
{
|
|
dlg.setMessage("작업 실행\n" +
|
|
"홈(QC) 위치로 하차를 진행 할까요?\n" +
|
|
"대상위치 : QC\n" +
|
|
"현재위치 : " + PUB.Result.CurrentPos.ToString());
|
|
if (dlg.ShowDialog() == DialogResult.Yes)
|
|
{
|
|
//아이템이 있으면 하차이고 없으면 상차이다
|
|
PUB.sm.ClearRunStep();
|
|
PUB.Result.TargetPos = ePosition.QC;
|
|
PUB.sm.SetNewRunStep(ERunStep.GODOWN);
|
|
PUB.sm.SetNewStep(eSMStep.RUN);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
dlg.setMessage("작업 실행\n" +
|
|
"홈(QC) 위치로 이동을 실행 할까요?\n" +
|
|
"대상위치 : QC\n" +
|
|
"현재위치 : " + PUB.Result.CurrentPos.ToString());
|
|
|
|
if (dlg.ShowDialog() == DialogResult.Yes)
|
|
{
|
|
|
|
//아이템이 있으면 하차이고 없으면 상차이다
|
|
PUB.sm.ClearRunStep();
|
|
PUB.Result.TargetPos = ePosition.QC;
|
|
PUB.sm.SetNewRunStep(ERunStep.GOHOME);
|
|
PUB.sm.SetNewStep(eSMStep.RUN);
|
|
}
|
|
}
|
|
|
|
break;
|
|
case ePosition.F1: //FVI영역은 모두 상차이동
|
|
dlg.setMessage("작업 실행\n" +
|
|
"(상차) 작업을 실행 할까요?\n" +
|
|
"대상위치 : FVI-1\n" +
|
|
"현재위치 : " + PUB.Result.CurrentPos.ToString());
|
|
if (dlg.ShowDialog() == DialogResult.Yes)
|
|
{
|
|
PUB.Result.TargetPos = ePosition.F1;
|
|
PUB.sm.SetNewRunStep(ERunStep.GOUP);
|
|
PUB.sm.SetNewStep(eSMStep.RUN);
|
|
}
|
|
|
|
break;
|
|
case ePosition.F2:
|
|
dlg.setMessage("작업 실행\n" +
|
|
"(상차) 작업을 실행 할까요?\n" +
|
|
"대상위치 : FVI-2\n" +
|
|
"현재위치 : " + PUB.Result.CurrentPos.ToString());
|
|
if (dlg.ShowDialog() == DialogResult.Yes)
|
|
{
|
|
|
|
PUB.Result.TargetPos = ePosition.F2;
|
|
PUB.sm.SetNewRunStep(ERunStep.GOUP);
|
|
PUB.sm.SetNewStep(eSMStep.RUN);
|
|
}
|
|
|
|
break;
|
|
case ePosition.F3:
|
|
dlg.setMessage("작업 실행\n" +
|
|
"(상차) 작업을 실행 할까요?\n" +
|
|
"대상위치 : FVI-3\n" +
|
|
"현재위치 : " + PUB.Result.CurrentPos.ToString());
|
|
if (dlg.ShowDialog() == DialogResult.Yes)
|
|
{
|
|
|
|
PUB.Result.TargetPos = ePosition.F3;
|
|
PUB.sm.SetNewRunStep(ERunStep.GOUP);
|
|
PUB.sm.SetNewStep(eSMStep.RUN);
|
|
//VAR.BOOL[eVarBool.FLAG_AUTORUN] = true;
|
|
}
|
|
|
|
break;
|
|
case ePosition.F4:
|
|
dlg.setMessage("작업 실행\n" +
|
|
"(상차) 작업을 실행 할까요?\n" +
|
|
"대상위치 : FVI-4\n" +
|
|
"현재위치 : " + PUB.Result.CurrentPos.ToString());
|
|
if (dlg.ShowDialog() == DialogResult.Yes)
|
|
{
|
|
|
|
PUB.Result.TargetPos = ePosition.F4;
|
|
PUB.sm.SetNewRunStep(ERunStep.GOUP);
|
|
PUB.sm.SetNewStep(eSMStep.RUN);
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
if (dlg != null) dlg.Dispose();
|
|
}
|
|
|
|
private void demoRunToolStripMenuItem_Click(object sender, EventArgs e)
|
|
{
|
|
PUB.Result.JobEndTime = DateTime.Now;
|
|
}
|
|
|
|
private void setZValidToolStripMenuItem_Click(object sender, EventArgs e)
|
|
{
|
|
PUB.log.Add("user set z-home set on");
|
|
}
|
|
|
|
private void errorToolStripMenuItem_Click(object sender, EventArgs e)
|
|
{
|
|
PUB.popup.setMessage("error\berror message");
|
|
}
|
|
|
|
private void informationToolStripMenuItem_Click(object sender, EventArgs e)
|
|
{
|
|
PUB.popup.setMessage("info\ninformation message", MessageWindow.eWindowType.information);
|
|
}
|
|
|
|
private void attentionToolStripMenuItem_Click(object sender, EventArgs e)
|
|
{
|
|
PUB.popup.setMessage("attention\nattention message", MessageWindow.eWindowType.attention);
|
|
}
|
|
|
|
|
|
private void btShowManual_Click(object sender, EventArgs e)
|
|
{
|
|
string file = System.IO.Path.Combine(UTIL.CurrentPath, "manual.pdf");
|
|
if (System.IO.File.Exists(file) == false)
|
|
{
|
|
UTIL.MsgE("사용설명서 파일이 존재하지 않습니다\n" +
|
|
"문의 : T8567 (장비기술 1파트)\n" +
|
|
"파일명 : " + file);
|
|
return;
|
|
}
|
|
UTIL.RunExplorer(file);
|
|
}
|
|
|
|
private void btClose_Click(object sender, EventArgs e)
|
|
{
|
|
this.Close();
|
|
}
|
|
|
|
private void arLabel5_Click(object sender, EventArgs e)
|
|
{
|
|
//SetScreen(form_setup);
|
|
|
|
|
|
var popmsg = PUB.popup.Visible;
|
|
PUB.popup.Visible = false;
|
|
VAR.BOOL[eVarBool.FLAG_SETUP] = true;
|
|
using (var f = new fSetup())
|
|
if (f.ShowDialog() == DialogResult.OK)
|
|
{
|
|
|
|
|
|
//AGV정보 싱크
|
|
PUB.sm.ResetRunStepSeq();
|
|
PUB.sm.SetNewStep(eSMStep.SYNC);
|
|
}
|
|
|
|
VAR.BOOL[eVarBool.FLAG_SETUP] = false;// VAR.BOOL[eVarBool.FLAG_SETUP] = false;//VAR.BOOL[eVarBool.FLAG_SETUP] = false;
|
|
|
|
if (popmsg) PUB.popup.Visible = true;
|
|
}
|
|
|
|
private void btMReset_Click(object sender, EventArgs e)
|
|
{
|
|
|
|
//if (Pub.sm.Step != eSMStep.IDLE)
|
|
//{
|
|
var dlg = UTIL.MsgQ(
|
|
"프로그램 상태를 초기화 하시겠습니까?\n" +
|
|
"진행 중인 사항은 모두 취소 됩니다");
|
|
if (dlg != System.Windows.Forms.DialogResult.Yes) return;
|
|
//}
|
|
//else Pub.log.AddAT("대기상태일때에는 초기화 할 수 없습니다");
|
|
|
|
PUB.log.Add("User Click : initialize", false);
|
|
PUB.sm.ClearRunStep();
|
|
PUB.sm.SetNewStep(eSMStep.RESET);
|
|
PUB.sm.bPause = false;
|
|
if (PUB.mplayer != null && PUB.mplayer.SoundLocation.isEmpty() == false)
|
|
{
|
|
PUB.mplayer.Stop();
|
|
PUB.bPlayMusic = false;
|
|
}
|
|
}
|
|
|
|
private void btCapture_Click(object sender, EventArgs e)
|
|
{
|
|
UTIL.ScreenCapture(Screen.PrimaryScreen.WorkingArea.Width, Screen.PrimaryScreen.WorkingArea.Height, new Point(0, 0));
|
|
}
|
|
|
|
private void btOpenDir_Click(object sender, EventArgs e)
|
|
{
|
|
UTIL.RunExplorer(UTIL.CurrentPath);
|
|
}
|
|
|
|
private void ManualMan_Click(object sender, EventArgs e)
|
|
{
|
|
SetScreen(form_manu);
|
|
MenuMAN.ForeColor = Color.Gold;
|
|
}
|
|
|
|
private void MenuLift_Click(object sender, EventArgs e)
|
|
{
|
|
SetScreen(form_zlift);
|
|
MenuLift.ForeColor = Color.Gold;
|
|
}
|
|
|
|
private void btDebug_Click(object sender, EventArgs e)
|
|
{
|
|
arCtl.arLabel ctl = sender as arCtl.arLabel;
|
|
this.cmDebug.Show(ctl, new Point((int)(ctl.Width / 1.5), (int)(ctl.Height / 1.5)));
|
|
}
|
|
|
|
private void btAutorun_Click(object sender, EventArgs e)
|
|
{
|
|
var ctl = sender as arCtl.arLabel;
|
|
if (ctl.Enabled == false) return;
|
|
PUB.log.Add("User Click : Start", false);
|
|
func_sw_start(true);
|
|
}
|
|
|
|
private void btMenuAuto_Click(object sender, EventArgs e)
|
|
{
|
|
SetScreen(form_auto);
|
|
MenuAuto.ForeColor = Color.Gold;
|
|
}
|
|
|
|
private void btMenuFlag_Click(object sender, EventArgs e)
|
|
{
|
|
SetScreen(form_flag);
|
|
MenuFlag.ForeColor = Color.Gold;
|
|
}
|
|
|
|
private void btLog_Click(object sender, EventArgs e)
|
|
{
|
|
if (form_log == null || form_log.IsDisposed || form_log.Disposing)
|
|
form_log = new Dialog.fLog();
|
|
|
|
form_log.Show();
|
|
form_log.Activate();
|
|
if (form_log.WindowState == FormWindowState.Minimized)
|
|
form_log.WindowState = FormWindowState.Normal;
|
|
}
|
|
|
|
|
|
private void btCharge_Click(object sender, EventArgs e)
|
|
{
|
|
var bCharge =
|
|
(PUB.sm.RunStep == ERunStep.GOCHARGE || PUB.sm.RunStep == ERunStep.CHARGECHECK || VAR.BOOL[eVarBool.FLAG_CHARGEONA] == true);
|
|
|
|
if (VAR.BOOL[eVarBool.FLAG_CHARGEONM])
|
|
{
|
|
UTIL.MsgE("수동 충전 상태이므로 진행 할 수 없습니다");
|
|
return;
|
|
}
|
|
|
|
//충전을 시작해라ㅏ
|
|
if (bCharge == true)
|
|
{
|
|
var dlg = UTIL.MsgQ("충전을 중지할까요?");
|
|
if (dlg == DialogResult.Yes)
|
|
{
|
|
PUB.sm.ClearRunStep();
|
|
PUB.sm.SetNewRunStep(ERunStep.GOHOME);
|
|
PUB.sm.SetNewStep(eSMStep.RUN);
|
|
PUB.log.Add("사용자 충전 해제");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
var dlg = UTIL.MsgQ("충전을 시작할까요?");
|
|
if (dlg == DialogResult.Yes)
|
|
{
|
|
PUB.sm.ClearRunStep();
|
|
PUB.sm.SetNewRunStep(ERunStep.GOCHARGE);
|
|
PUB.sm.SetNewStep(eSMStep.RUN);
|
|
PUB.log.Add("충전(사용자)작업 시작");
|
|
}
|
|
}
|
|
}
|
|
|
|
private void pictureBox1_Click(object sender, EventArgs e)
|
|
{
|
|
using (var f = new Dialog.fSystem())
|
|
{
|
|
f.ShowDialog();
|
|
if (f.shutdown)
|
|
{
|
|
forceClose = true;
|
|
this.Close();
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
private void SSInfo_Click(object sender, EventArgs e)
|
|
{
|
|
PUB.Speak("고경석 수석님 밥은 드셨습니까?", true);
|
|
UpdateProgressStatus(20, 100, "progre");
|
|
}
|
|
private void brHome_Click(object sender, EventArgs e)
|
|
{
|
|
var bCharge = PUB.sm.Step == eSMStep.RUN &&
|
|
(PUB.sm.RunStep == ERunStep.GOHOME);
|
|
|
|
if (PUB.CheckManualChargeMode() == false) return;
|
|
|
|
if (bCharge == true)
|
|
{
|
|
var dlg = UTIL.MsgQ("홈(QC) 이동을 취소 할까요?");
|
|
if (dlg == DialogResult.Yes)
|
|
{
|
|
PUB.sm.ClearRunStep();
|
|
PUB.sm.SetNewStep(eSMStep.IDLE);
|
|
PUB.AGV.AGVMoveStop("user home cancle", arDev.Narumi.eStopOpt.Stop);
|
|
//PUB.AGV.AddCommand(arDev.Narumi.eAgvCmd.MoveStop);//.Move(Device.PLC.Rundirection.Stop, "사용자 홈 이동 취소");
|
|
PUB.log.Add("사용자 홈 이동 취소");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
var dlg = UTIL.MsgQ("홈(QC) 이동을 실행 할까요?");
|
|
if (dlg == DialogResult.Yes)
|
|
{
|
|
PUB.sm.ClearRunStep();
|
|
PUB.sm.SetNewRunStep(ERunStep.GOHOME);
|
|
PUB.sm.SetNewStep(eSMStep.RUN);
|
|
PUB.log.Add("사용자 홈 이동 실행");
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
|
|
private void btTopMenu_Volume_Click_1(object sender, EventArgs e)
|
|
{
|
|
using (var f = new Dialog.fVolume())
|
|
f.ShowDialog();
|
|
}
|
|
|
|
private void lbCNtUp_Click(object sender, EventArgs e)
|
|
{
|
|
//down,up둘다 연결해야함
|
|
using (var f = new Dialog.fCounter())
|
|
f.ShowDialog();
|
|
}
|
|
|
|
private void btMenuAGV_Click_1(object sender, EventArgs e)
|
|
{
|
|
SetScreen(form_agv);
|
|
MenuAGV.ForeColor = Color.Gold;
|
|
}
|
|
|
|
private void btMenuBMS_Click_1(object sender, EventArgs e)
|
|
{
|
|
SetScreen(form_bms);
|
|
MenuBMS.ForeColor = Color.Gold;
|
|
}
|
|
|
|
private void lbBat_Click(object sender, EventArgs e)
|
|
{
|
|
var bat = (int)PUB.BMS.Current_Level;
|
|
var msg = $"{bat}퍼센트";
|
|
PUB.Speak(msg, false, false);
|
|
PUB.counter.CountQA += 1;
|
|
}
|
|
private void IOState_ItemClick_1(object sender, arFrame.Control.GridView.ItemClickEventArgs e)
|
|
{
|
|
var title = IOState.Titles[e.idx];
|
|
switch (title.ToLower())
|
|
{
|
|
case "emg":
|
|
PUB.AGV.AGVErrorReset();
|
|
break;
|
|
case "itm":
|
|
var itemon = VAR.BOOL[eVarBool.ITEMON];
|
|
VAR.BOOL[eVarBool.ITEMON] = !itemon;
|
|
break;
|
|
}
|
|
}
|
|
|
|
private void btChargeM_Click(object sender, EventArgs e)
|
|
{
|
|
if (VAR.BOOL[eVarBool.FLAG_CHARGEONM])
|
|
{
|
|
var dlg = UTIL.MsgQ("수동 충전을 해제 할까요?");
|
|
if (dlg != DialogResult.Yes) return;
|
|
VAR.BOOL[eVarBool.FLAG_CHARGEONM] = false;
|
|
PUB.log.Add("수동 충전 실행");
|
|
}
|
|
else
|
|
{
|
|
if (PUB.AGV.system1.Battery_charging)
|
|
{
|
|
UTIL.MsgE("현재 자동 충전 중이라 진행 할 수 없습니다");
|
|
return;
|
|
}
|
|
var dlg = UTIL.MsgQ("수동 충전을 진행 할까요?");
|
|
if (dlg != DialogResult.Yes) return;
|
|
VAR.BOOL[eVarBool.FLAG_CHARGEONM] = true;
|
|
PUB.log.Add("수동 충전 실행");
|
|
}
|
|
}
|
|
|
|
private void saveToolStripMenuItem_Click(object sender, EventArgs e)
|
|
{
|
|
//mapsave
|
|
using (var sd = new SaveFileDialog())
|
|
{
|
|
sd.Filter = "AGV Map Files (*.agvmap)|*.agvmap|All Files (*.*)|*.*";
|
|
sd.DefaultExt = "agvmap";
|
|
sd.FileName = PUB._mapCanvas.MapFileName;
|
|
if (sd.ShowDialog() == DialogResult.OK)
|
|
{
|
|
SaveMapToFile(sd.FileName);
|
|
}
|
|
}
|
|
}
|
|
|
|
private void loadToolStripMenuItem_Click(object sender, EventArgs e)
|
|
{
|
|
//load
|
|
|
|
var od = new OpenFileDialog
|
|
{
|
|
Filter = "AGV Map Files (*.agvmap)|*.agvmap|All Files (*.*)|*.*",
|
|
DefaultExt = "agvmap",
|
|
FileName = PUB._mapCanvas.MapFileName,
|
|
};
|
|
|
|
if (od.ShowDialog() == DialogResult.OK)
|
|
{
|
|
try
|
|
{
|
|
LoadMapFromFile(od.FileName);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
MessageBox.Show($"맵 로드 중 오류가 발생했습니다: {ex.Message}", "오류", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
|
}
|
|
}
|
|
}
|
|
|
|
private void LoadMapFromFile(string filePath)
|
|
{
|
|
var result = MapLoader.LoadMapFromFile(filePath);
|
|
|
|
if (result.Success)
|
|
{
|
|
var _mapCanvas = PUB._mapCanvas;
|
|
PUB._mapNodes = result.Nodes;
|
|
|
|
// 맵 캔버스에 데이터 설정
|
|
_mapCanvas.Nodes = result.Nodes;
|
|
// RfidMappings 제거됨 - MapNode에 통합
|
|
|
|
// 🔥 맵 설정 적용 (배경색, 그리드 표시)
|
|
if (result.Settings != null)
|
|
{
|
|
_mapCanvas.BackColor = System.Drawing.Color.FromArgb(result.Settings.BackgroundColorArgb);
|
|
_mapCanvas.ShowGrid = result.Settings.ShowGrid;
|
|
}
|
|
|
|
// 설정에 마지막 맵 파일 경로 저장
|
|
PUB.setting.LastMapFile = filePath;
|
|
PUB.setting.Save();
|
|
|
|
// 맵 로드 후 자동으로 맵에 맞춤
|
|
_mapCanvas.FitToNodes();
|
|
}
|
|
else
|
|
{
|
|
MessageBox.Show($"맵 파일 로딩 실패: {result.ErrorMessage}", "오류",
|
|
MessageBoxButtons.OK, MessageBoxIcon.Error);
|
|
}
|
|
}
|
|
|
|
private void SaveMapToFile(string filePath)
|
|
{
|
|
// 🔥 백업 파일 생성 (기존 파일이 있을 경우)
|
|
if (File.Exists(filePath))
|
|
{
|
|
try
|
|
{
|
|
// 날짜시간 포함 백업 파일명 생성
|
|
var directory = Path.GetDirectoryName(filePath);
|
|
var fileNameWithoutExt = Path.GetFileNameWithoutExtension(filePath);
|
|
var extension = Path.GetExtension(filePath);
|
|
var timestamp = DateTime.Now.ToString("yyyyMMdd_HHmmss");
|
|
var backupFileName = $"{fileNameWithoutExt}_{timestamp}{extension}.bak";
|
|
var backupFilePath = Path.Combine(directory, backupFileName);
|
|
|
|
// 기존 파일을 백업 파일로 복사
|
|
File.Copy(filePath, backupFilePath, true);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
// 백업 파일 생성 실패 시 경고만 표시하고 계속 진행
|
|
MessageBox.Show($"백업 파일 생성 실패: {ex.Message}\n원본 파일은 계속 저장됩니다.", "백업 경고",
|
|
MessageBoxButtons.OK, MessageBoxIcon.Warning);
|
|
}
|
|
}
|
|
|
|
var _mapCanvas = PUB._mapCanvas;
|
|
var _mapNodes = PUB._mapNodes;
|
|
|
|
// 🔥 현재 캔버스 설정을 맵 파일에 저장
|
|
var settings = new MapLoader.MapSettings
|
|
{
|
|
BackgroundColorArgb = _mapCanvas.BackColor.ToArgb(),
|
|
ShowGrid = _mapCanvas.ShowGrid
|
|
};
|
|
|
|
if (MapLoader.SaveMapToFile(filePath, _mapNodes, settings))
|
|
{
|
|
// 설정에 마지막 맵 파일 경로 저장
|
|
PUB.setting.LastMapFile = filePath;
|
|
PUB.setting.Save();
|
|
}
|
|
else
|
|
{
|
|
MessageBox.Show("맵 파일 저장 실패", "오류",
|
|
MessageBoxButtons.OK, MessageBoxIcon.Error);
|
|
}
|
|
}
|
|
|
|
private void DumpAllThreadsState()
|
|
{
|
|
try
|
|
{
|
|
var sb = new System.Text.StringBuilder();
|
|
sb.AppendLine("===== 스레드 상태 덤프 =====");
|
|
sb.AppendLine($"시간: {DateTime.Now:yyyy-MM-dd HH:mm:ss.fff}");
|
|
sb.AppendLine($"마지막 sm_Running 호출: {(DateTime.Now - lastSmRunningTime).TotalSeconds:F1}초 전");
|
|
sb.AppendLine($"sm_Running 호출 횟수: {sm_Running_CallCount}");
|
|
sb.AppendLine($"IsThreadRun: {PUB.sm.IsThreadRun}");
|
|
sb.AppendLine($"Current Step: {PUB.sm.Step}");
|
|
sb.AppendLine($"Current RunStep: {PUB.sm.RunStep}");
|
|
sb.AppendLine();
|
|
|
|
var process = System.Diagnostics.Process.GetCurrentProcess();
|
|
sb.AppendLine($"총 스레드 수: {process.Threads.Count}");
|
|
sb.AppendLine();
|
|
|
|
foreach (System.Diagnostics.ProcessThread thread in process.Threads)
|
|
{
|
|
sb.AppendLine($"Thread {thread.Id}:");
|
|
sb.AppendLine($" State: {thread.ThreadState}");
|
|
sb.AppendLine($" Priority: {thread.PriorityLevel}");
|
|
if (thread.ThreadState == System.Diagnostics.ThreadState.Wait)
|
|
{
|
|
sb.AppendLine($" WaitReason: {thread.WaitReason}");
|
|
}
|
|
sb.AppendLine();
|
|
}
|
|
|
|
var dump = sb.ToString();
|
|
PUB.log.Add("THREAD_DUMP", dump);
|
|
Console.WriteLine(dump);
|
|
|
|
MessageBox.Show(
|
|
$"스레드 덤프 완료\n로그 파일에 저장되었습니다.\n\n" +
|
|
$"마지막 sm_Running: {(DateTime.Now - lastSmRunningTime).TotalSeconds:F1}초 전\n" +
|
|
$"IsThreadRun: {PUB.sm.IsThreadRun}",
|
|
"스레드 덤프",
|
|
MessageBoxButtons.OK,
|
|
MessageBoxIcon.Information);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
PUB.log.AddE($"DumpAllThreadsState 오류: {ex.Message}");
|
|
}
|
|
}
|
|
|
|
private void stateMachineDebugToolStripMenuItem_Click(object sender, EventArgs e)
|
|
{
|
|
try
|
|
{
|
|
var debugForm = new Dialog.fStateMachineDebug();
|
|
debugForm.Show();
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
MessageBox.Show($"디버그 창을 열 수 없습니다:\n{ex.Message}", "오류",
|
|
MessageBoxButtons.OK, MessageBoxIcon.Error);
|
|
}
|
|
}
|
|
|
|
private void editorToolStripMenuItem_Click(object sender, EventArgs e)
|
|
{
|
|
try
|
|
{
|
|
// MapEditor 실행 파일 경로 확인
|
|
string mapEditorPath = "AGVMapEditor.exe";
|
|
|
|
// 경로가 설정되지 않았거나 파일이 없는 경우 사용자에게 선택을 요청
|
|
if (string.IsNullOrEmpty(mapEditorPath) || !File.Exists(mapEditorPath))
|
|
{
|
|
using (var openDialog = new OpenFileDialog())
|
|
{
|
|
openDialog.Filter = "실행 파일 (*.exe)|*.exe|모든 파일 (*.*)|*.*";
|
|
openDialog.Title = "AGV MapEditor 실행 파일 선택";
|
|
openDialog.InitialDirectory = Application.StartupPath;
|
|
|
|
if (openDialog.ShowDialog() == DialogResult.OK)
|
|
{
|
|
mapEditorPath = openDialog.FileName;
|
|
}
|
|
else
|
|
{
|
|
return; // 사용자가 취소함
|
|
}
|
|
}
|
|
}
|
|
|
|
// MapEditor 실행
|
|
var startInfo = new System.Diagnostics.ProcessStartInfo
|
|
{
|
|
FileName = mapEditorPath,
|
|
UseShellExecute = true
|
|
};
|
|
|
|
// 현재 로드된 맵 파일이 있으면 파라미터로 전달
|
|
var _currentMapFilePath = PUB._mapCanvas.MapFileName;
|
|
if (!string.IsNullOrEmpty(_currentMapFilePath) && File.Exists(_currentMapFilePath))
|
|
{
|
|
startInfo.Arguments = $"\"{_currentMapFilePath}\"";
|
|
}
|
|
|
|
System.Diagnostics.Process.Start(startInfo);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
MessageBox.Show($"MapEditor를 실행할 수 없습니다:\n{ex.Message}", "오류",
|
|
MessageBoxButtons.OK, MessageBoxIcon.Error);
|
|
}
|
|
}
|
|
}
|
|
}
|