782 lines
29 KiB
C#
782 lines
29 KiB
C#
using COMM;
|
|
using System.Net.NetworkInformation;
|
|
using System.Net;
|
|
using System.Management;
|
|
using System.Data;
|
|
using AR;
|
|
using System.Media;
|
|
using System.Runtime.InteropServices;
|
|
using System.Windows.Forms;
|
|
using System;
|
|
|
|
#if SPEECH
|
|
using Microsoft.Speech.Synthesis;
|
|
#endif
|
|
|
|
using System.Threading.Tasks;
|
|
using System.Data.SqlClient;
|
|
using System.Linq;
|
|
using AGVNavigationCore.Models;
|
|
using AGVNavigationCore.Controls;
|
|
using System.Collections.Generic;
|
|
using System.Drawing;
|
|
|
|
namespace Project
|
|
{
|
|
public static class PUB
|
|
{
|
|
//public static Device.CFlag flag;
|
|
public static bool bShutdown = false;
|
|
public static bool Automodeonreboot = false;
|
|
public static bool AutRebootAlreay = false;
|
|
public static bool DriveSpeed = false;
|
|
public static AGVNavigationCore.Controls.UnifiedAGVCanvas _mapCanvas;
|
|
public static List<MapNode> _mapNodes;
|
|
|
|
/// <summary>
|
|
/// 가상 AGV (시뮬레이션용)
|
|
/// </summary>
|
|
public static VirtualAGV _virtualAGV;
|
|
|
|
#region "Hardware"
|
|
|
|
/// <summary>
|
|
/// 읽기/쓰기용이며 구동모터 와 비상정지가 연결됨(USB-ATMEGA 2560)
|
|
/// </summary>
|
|
//public static arDev.FakePLC PLC;
|
|
|
|
///// <summary>
|
|
///// 읽기전용이며 Z축 모터와 외부 버튼이 연결됨(USB-ATMEGA 2560)
|
|
///// </summary>
|
|
//public static Device.PLC2 plcS;
|
|
|
|
/// <summary>
|
|
/// XBEE 통신(USB-TTL)
|
|
/// </summary>
|
|
public static Device.Xbee XBE;
|
|
|
|
/// <summary>
|
|
/// 배터리 잔량 확인(COM2 : RS232C - TTL)
|
|
/// </summary>
|
|
// public static arDevice.BMS bms;
|
|
|
|
/// <summary>
|
|
/// RFID READER (COM1 : RS232C)
|
|
/// </summary>
|
|
public static arDev.Narumi AGV;
|
|
|
|
public static arDev.BMS BMS;
|
|
|
|
#endregion
|
|
|
|
/// <summary>
|
|
/// 디버그모니터용 소켓(데이터를 전송만 한다)
|
|
/// </summary>
|
|
public static Device.Socket sock_debug;
|
|
#if SPEECH
|
|
private static SpeechSynthesizer voice;
|
|
#endif
|
|
public static SoundPlayer mplayer;
|
|
|
|
[DllImport("winmm.dll")]
|
|
private static extern int waveOutSetVolume(IntPtr hwo, uint dwVolume);
|
|
|
|
public static void SetVolume(int volume)
|
|
{
|
|
// volume은 0~100 사이의 값
|
|
uint vol = (uint)((volume / 100.0) * 0xFFFF);
|
|
waveOutSetVolume(IntPtr.Zero, vol);
|
|
setting.musicvol = volume;
|
|
}
|
|
|
|
public static bool CheckPassword()
|
|
{
|
|
var f = new Dialog.fPassword();
|
|
if (f.ShowDialog() != System.Windows.Forms.DialogResult.OK) return false;
|
|
var pass = f.tbInput.Text.Trim();
|
|
var passok = DateTime.Now.ToString("ddMM");
|
|
if (pass.Equals(passok)) return true;
|
|
else return false;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 스피커를 통한 음성을 출력합니다
|
|
/// 출력되는 음성은 기본로그에도 자동 포함됩니다
|
|
/// </summary>
|
|
/// <param name="m"></param>
|
|
/// <param name="force"></param>
|
|
/// <param name="addlog">로그에도 출력 합니다</param>
|
|
public static void Speak(string m, Boolean force = false, bool addlog = true,string logcate="")
|
|
{
|
|
if (force == false && PUB.setting.Enable_Speak == false)
|
|
{
|
|
Console.WriteLine("speech disabled");
|
|
return;
|
|
}
|
|
#if SPEECH
|
|
if (force)
|
|
voice.SpeakAsyncCancelAll();
|
|
if (voice.State == SynthesizerState.Ready)
|
|
voice.SpeakAsync(m);
|
|
if (addlog)
|
|
{
|
|
if (logcate.isEmpty()) logcate = "SPEAK";
|
|
PUB.log.Add(logcate, m);
|
|
}
|
|
#else
|
|
PUB.log.Add($"스피치컴파일상수OFF");
|
|
#endif
|
|
}
|
|
|
|
/// <summary>
|
|
/// 콜을 받을 수 있는 상황인가?
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
public static bool IsCanCALL()
|
|
{
|
|
//콜가능여부도 전송한다
|
|
if (VAR.BOOL[eVarBool.FLAG_AUTORUN] &&
|
|
VAR.BOOL[eVarBool.FLAG_CHARGEONM] == false &&
|
|
PUB.BMS.Current_Level > PUB.setting.ChargeEmergencyLevel &&
|
|
PUB.sm.RunStep != StateMachine.ERunStep.BUFFER_OUT &&
|
|
VAR.BOOL[eVarBool.WAIT_COVER_DOWN] == false &&
|
|
VAR.BOOL[eVarBool.WAIT_COVER_UP] == false)
|
|
{
|
|
return true;
|
|
}
|
|
else return false;
|
|
}
|
|
|
|
public static CounterSetting counter;
|
|
|
|
/// <summary>
|
|
/// popup message window
|
|
/// </summary>
|
|
public static MessageWindow popup;
|
|
|
|
/// <summary>
|
|
/// database manager
|
|
/// </summary>
|
|
public static Manager.DatabaseManager dbm;
|
|
|
|
/// <summary>
|
|
/// 설정정보
|
|
/// </summary>
|
|
public static CSetting setting;
|
|
|
|
/// <summary>
|
|
/// 시스템로그
|
|
/// </summary>
|
|
public static AR.Log log, logagv, logplc, logbms, logxbee;
|
|
|
|
public static Boolean bPlayMusic = false;
|
|
|
|
|
|
/// <summary>
|
|
/// 사용자 인풋 감지 시간
|
|
/// </summary>
|
|
public static DateTime LastInputTime = DateTime.Now;
|
|
|
|
public static CResult Result;
|
|
|
|
public static string PatchVersion { get; set; }
|
|
|
|
/// <summary>
|
|
/// 상태머신
|
|
/// </summary>
|
|
public static StateMachine.StateMachine sm; //상태머신분리 190529
|
|
|
|
public static System.IO.DirectoryInfo path;
|
|
|
|
|
|
public static void initCore()
|
|
{
|
|
//setting
|
|
setting = new CSetting();
|
|
setting.Load();
|
|
|
|
//counter setting
|
|
counter = new CounterSetting();
|
|
counter.Load();
|
|
|
|
//log
|
|
log = new AR.Log();
|
|
logagv = new AR.Log();
|
|
logplc = new AR.Log();
|
|
logbms = new AR.Log();
|
|
logxbee = new AR.Log();
|
|
|
|
logagv.FileNameFormat = "{yyyyMMdd}_agv";
|
|
logplc.FileNameFormat = "{yyyyMMdd}_plc";
|
|
logbms.FileNameFormat = "{yyyyMMdd}_bms";
|
|
logxbee.FileNameFormat = "{yyyyMMdd}_cal";
|
|
|
|
//popupmessage
|
|
popup = new MessageWindow();
|
|
|
|
Result = new CResult();
|
|
Result.Clear();
|
|
}
|
|
|
|
public static void init()
|
|
{
|
|
|
|
Result = new CResult();
|
|
|
|
//state machine
|
|
sm = new StateMachine.StateMachine();
|
|
|
|
path = new System.IO.DirectoryInfo(UTIL.CurrentPath);
|
|
|
|
|
|
|
|
mplayer = new SoundPlayer();
|
|
if (PUB.setting.musicfile.isEmpty() == false)
|
|
if (System.IO.File.Exists(PUB.setting.musicfile))
|
|
{
|
|
PUB.mplayer.SoundLocation = PUB.setting.musicfile;
|
|
SetVolume(PUB.setting.musicvol);
|
|
}
|
|
#if SPEECH
|
|
voice = new SpeechSynthesizer();
|
|
try
|
|
{
|
|
// 한국어 음성을 찾아서 설정
|
|
var koreanVoice = voice.GetInstalledVoices()
|
|
.Where(v => v.VoiceInfo.Culture.Name.StartsWith("ko"))
|
|
.FirstOrDefault();
|
|
|
|
if (koreanVoice != null)
|
|
{
|
|
voice.SelectVoice(koreanVoice.VoiceInfo.Name);
|
|
}
|
|
else
|
|
{
|
|
// 한국어 음성이 없으면 기본 음성 사용
|
|
var defaultVoice = voice.GetInstalledVoices().FirstOrDefault();
|
|
if (defaultVoice != null)
|
|
{
|
|
voice.SelectVoice(defaultVoice.VoiceInfo.Name);
|
|
}
|
|
}
|
|
}
|
|
catch
|
|
{
|
|
// 음성 설정 실패 시 기본값 사용
|
|
}
|
|
voice.SetOutputToDefaultAudioDevice();
|
|
#endif
|
|
var file_version = System.IO.Path.Combine(UTIL.CurrentPath, "version.txt");
|
|
if (System.IO.File.Exists(file_version))
|
|
{
|
|
PUB.PatchVersion = System.IO.File.ReadAllText(file_version, System.Text.Encoding.UTF8);
|
|
}
|
|
else PUB.PatchVersion = string.Empty;
|
|
}
|
|
|
|
|
|
|
|
public static Boolean CheckManualChargeMode(bool Prompt = true)
|
|
{
|
|
if (VAR.BOOL[eVarBool.FLAG_CHARGEONM] == true)
|
|
{
|
|
string msg = "수동 충전 상태이므로 진행 할 수 없습니다";
|
|
PUB.Speak(msg);
|
|
if (Prompt)
|
|
UTIL.MsgE(msg);
|
|
return false;
|
|
}
|
|
else return true;
|
|
}
|
|
|
|
public static double GetFreeSpace(string driveletter)
|
|
{
|
|
try
|
|
{
|
|
var di = new System.IO.DriveInfo(driveletter);
|
|
var freespace = di.TotalFreeSpace;
|
|
var totalspace = di.TotalSize;
|
|
var freeSpaceRate = (freespace * 1.0 / totalspace) * 100.0;
|
|
return freeSpaceRate;
|
|
}
|
|
catch
|
|
{
|
|
return 100.0;
|
|
}
|
|
}
|
|
|
|
public static double GetFreeSpace()
|
|
{
|
|
double retval = 100.0;
|
|
string savePath1 = path.FullName;
|
|
if (savePath1 != "" && System.IO.Directory.Exists(savePath1))
|
|
{
|
|
//이폴더를 사용
|
|
if (savePath1.StartsWith("\\") == false)
|
|
{
|
|
//남은잔량을 체크한다.
|
|
retval = GetFreeSpace(savePath1.Substring(0, 1));
|
|
//if (freespace1 >= Pub.setting.AutoDeleteThreshold) return savePath1;
|
|
}
|
|
}
|
|
return retval;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 장치에 오류가 있는지?
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
public static Boolean HasHWError()
|
|
{
|
|
//if (PUB.PLC.IsValid == false) return true;
|
|
if (PUB.AGV.IsOpen == false) return true;
|
|
if (PUB.XBE.IsOpen == false) return true;
|
|
return false;
|
|
}
|
|
|
|
//public static void AddStatusSQL(StateMachine.eSMStep status, string remark, DateTime wdate)
|
|
//{
|
|
// VAR.TIME[eVarTime.StatusReporttime] = DateTime.Now;
|
|
// try
|
|
// {
|
|
// var state = 0;
|
|
// if (status == StateMachine.eSMStep.RUN) state = 1;
|
|
// else if (status == StateMachine.eSMStep.ERROR || status == StateMachine.eSMStep.EMERGENCY) state = 2;
|
|
// if (string.IsNullOrEmpty(remark)) remark = status.ToString();
|
|
// var mcid = PUB.setting.MCID;
|
|
// var path = System.IO.Path.Combine(Util.CurrentPath, "Status");
|
|
// var file = System.IO.Path.Combine(path, $"{DateTime.Now.ToString("HHmmssfff")}_{status}.sql");
|
|
// var sql = "insert into MCMonitor_Rawdata(Model,status,remark,ip,mac,time) values('{0}','{1}','{2}','{3}','{4}','{5}')";
|
|
// sql = string.Format(sql, mcid, state, remark, IP, MAC, wdate.ToString("yyyy-MM-dd HH:mm:ss"));
|
|
// System.IO.File.WriteAllText(file, sql, System.Text.Encoding.Default);
|
|
|
|
// //만들어진지 3분이 지난 파일은 삭제한다.
|
|
// //var di = new System.IO.DirectoryInfo(path);
|
|
// //var fi = di.GetFiles("*.sql", System.IO.SearchOption.TopDirectoryOnly).Where(t => t.LastWriteTime < DateTime.Now.AddMinutes(-3)).FirstOrDefault();
|
|
// //if (fi != null) fi.Delete();
|
|
// }
|
|
// catch (Exception ex)
|
|
// {
|
|
// PUB.log.AddE(ex.Message);
|
|
// }
|
|
//}
|
|
|
|
public static void AddEEDB(string remark)
|
|
{
|
|
var step = PUB.sm.Step.ToString();
|
|
var rtep = PUB.sm.RunStep.ToString();
|
|
var mcid = PUB.setting.MCID;
|
|
var path = System.IO.Path.Combine(UTIL.CurrentPath, "Status");
|
|
var file = System.IO.Path.Combine(path, $"{DateTime.Now.ToString("HHmmssfff")}_{step}_{rtep}.sql");
|
|
var wdate = DateTime.Now;
|
|
try
|
|
{
|
|
var sql = "insert into AGV_History(mcid,step,runstep,remark,ip,wdate) values('{0}','{1}','{2}','{3}','{4}','{5}')";
|
|
sql = string.Format(sql, mcid, step, rtep, remark, IP, wdate.ToString("yyyy-MM-dd HH:mm:ss"));
|
|
System.IO.File.WriteAllText(file, sql, System.Text.Encoding.Default);
|
|
|
|
//만들어진지 3분이 지난 파일은 삭제한다.
|
|
//var di = new System.IO.DirectoryInfo(path);
|
|
//var fi = di.GetFiles("*.sql", System.IO.SearchOption.TopDirectoryOnly).Where(t => t.LastWriteTime < DateTime.Now.AddMinutes(-3)).FirstOrDefault();
|
|
//if (fi != null) fi.Delete();
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
PUB.log.AddE(ex.Message);
|
|
}
|
|
}
|
|
|
|
public static string GetResultCodeMessage(eResult err)
|
|
{
|
|
return err.ToString().ToUpper();
|
|
}
|
|
|
|
|
|
public static string GetErrorMessage(eECode err, params object[] values)
|
|
{
|
|
switch (err)
|
|
{
|
|
case eECode.NOTALLOWUP:
|
|
return "상차 허용 위치가 아닙니다";
|
|
case eECode.AGVCONN:
|
|
return Lang.AGV연결실패;
|
|
case eECode.PLCCONN:
|
|
return Lang.PLC통신실패;
|
|
case eECode.MESSAGE_ERROR:
|
|
if (values.Length > 0) return values[0].ToString();
|
|
return "Message Error";
|
|
|
|
default:
|
|
return err.ToString();
|
|
}
|
|
}
|
|
public static string IP { get; set; }
|
|
public static string MAC { get; set; }
|
|
|
|
/// <summary>
|
|
/// 프로그램 사용기록 추가
|
|
/// </summary>
|
|
/// <param name="prgmName"></param>
|
|
/// <param name="develop"></param>
|
|
/// <param name="prgmVersion"></param>
|
|
public static void CheckNRegister3(string prgmName, string develop, string prgmVersion)
|
|
{
|
|
if (prgmName.Length > 50) prgmName = prgmName.Substring(0, 50); //길이제한
|
|
var task = Task.Factory.StartNew(() =>
|
|
{
|
|
try
|
|
{
|
|
string ip = "";
|
|
string mac = "";
|
|
// string prgmName = Application.ProductName;
|
|
|
|
var nif = NetworkInterface.GetAllNetworkInterfaces();
|
|
var host = Dns.GetHostEntry(Dns.GetHostName());
|
|
string fullname = System.Net.Dns.GetHostEntry("").HostName;
|
|
foreach (IPAddress r in host.AddressList)
|
|
{
|
|
string str = r.ToString();
|
|
|
|
if (str != "" && str.Substring(0, 3) == "10.")
|
|
{
|
|
ip = str;
|
|
break;
|
|
}
|
|
}
|
|
|
|
string rtn = string.Empty;
|
|
ObjectQuery oq = new System.Management.ObjectQuery("SELECT * FROM Win32_NetworkAdapterConfiguration WHERE IPEnabled='TRUE'");
|
|
ManagementObjectSearcher query1 = new ManagementObjectSearcher(oq);
|
|
foreach (ManagementObject mo in query1.Get())
|
|
{
|
|
string[] address = (string[])mo["IPAddress"];
|
|
if (address[0] == ip && mo["MACAddress"] != null)
|
|
{
|
|
mac = mo["MACAddress"].ToString();
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (ip == "" || mac == "") return;
|
|
|
|
var conn = new SqlConnection(AGV4.Properties.Settings.Default.CS);// "Data Source=10.131.15.18;Initial Catalog=EE;Persist Security Info=True;User ID=eeuser;Password=Amkor123!");
|
|
conn.Open();
|
|
string ProcName = "AddPrgmUser3";
|
|
var cmd = new SqlCommand(ProcName, conn)
|
|
{
|
|
CommandType = CommandType.StoredProcedure
|
|
};
|
|
|
|
SqlParameter param = cmd.Parameters.Add("@mac", SqlDbType.NVarChar, 50);
|
|
param.Value = mac;
|
|
|
|
param = cmd.Parameters.Add("@ip", SqlDbType.NVarChar, 50);
|
|
param.Value = ip;
|
|
|
|
param = cmd.Parameters.Add("@pgrm", SqlDbType.NVarChar, 50);
|
|
param.Value = prgmName;
|
|
|
|
param = cmd.Parameters.Add("@develop", SqlDbType.NVarChar, 50);
|
|
param.Value = develop;
|
|
|
|
param = cmd.Parameters.Add("@pgver", SqlDbType.NVarChar, 50);
|
|
param.Value = prgmVersion;
|
|
|
|
param = cmd.Parameters.Add("@prgmLogin", SqlDbType.VarChar, 20);
|
|
param.Value = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
|
|
|
|
param = cmd.Parameters.Add("@account", SqlDbType.NVarChar, 50);
|
|
param.Value = System.Environment.UserName;
|
|
|
|
param = cmd.Parameters.Add("@hostname", SqlDbType.NVarChar, 100);
|
|
param.Value = fullname;
|
|
|
|
cmd.ExecuteNonQuery();
|
|
conn.Close();
|
|
|
|
IP = ip;
|
|
MAC = mac;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
PUB.log.AddE(ex.Message);
|
|
}
|
|
});
|
|
}
|
|
public static string SelectSerialPort()
|
|
{
|
|
var f = new System.Windows.Forms.Form();
|
|
f.WindowState = System.Windows.Forms.FormWindowState.Normal;
|
|
f.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
|
|
f.Size = new System.Drawing.Size(800, 400);
|
|
f.MaximizeBox = false;
|
|
f.MinimizeBox = false;
|
|
f.Text = "Select Port";
|
|
f.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
|
|
var lst = new System.Windows.Forms.ListBox();
|
|
lst.Font = new System.Drawing.Font("Consolas", 15, System.Drawing.FontStyle.Bold);
|
|
lst.Dock = System.Windows.Forms.DockStyle.Fill;
|
|
lst.DoubleClick += (s1, e1) =>
|
|
{
|
|
if (lst.SelectedItem != null) f.DialogResult = System.Windows.Forms.DialogResult.OK;
|
|
};
|
|
using (var searcher = new ManagementObjectSearcher("SELECT * FROM WIN32_SerialPort"))
|
|
{
|
|
var portnames = System.IO.Ports.SerialPort.GetPortNames().OrderBy(t => t);
|
|
var ports = searcher.Get().Cast<ManagementBaseObject>().ToList();
|
|
foreach (var port in portnames)
|
|
{
|
|
var desc = "";
|
|
var portInfo = ports.Where(t => t["DeviceId"].ToString() == port).FirstOrDefault();
|
|
if (portInfo != null) desc = portInfo["Caption"].ToString();
|
|
lst.Items.Add(string.Format("{0} - {1}", port, desc));
|
|
}
|
|
}
|
|
f.Controls.Add(lst);
|
|
if (f.ShowDialog() == System.Windows.Forms.DialogResult.OK)
|
|
{
|
|
var name = lst.SelectedItem.ToString().Split('-');
|
|
return name[0].Trim();
|
|
}
|
|
else return string.Empty;
|
|
}
|
|
|
|
public static void SystemReboot(UInt16 timeout, bool setautomode = false)
|
|
{
|
|
System.Diagnostics.ProcessStartInfo si = new System.Diagnostics.ProcessStartInfo();
|
|
si.FileName = @"c:\windows\system32\shutdown.exe";
|
|
si.Arguments = "-r -t " + timeout.ToString();
|
|
si.UseShellExecute = false;
|
|
System.Diagnostics.Process prc = new System.Diagnostics.Process();
|
|
prc.StartInfo = si;
|
|
|
|
PUB.AGV.AGVMoveStop("user reboot");
|
|
|
|
if (setautomode)
|
|
{
|
|
PUB.Automodeonreboot = true;
|
|
PUB.setting.SetAutoModeOn = true;
|
|
PUB.setting.AUtoRebootLastTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
|
|
PUB.setting.Save();
|
|
}
|
|
|
|
|
|
prc.Start();
|
|
|
|
}
|
|
public static void SystemShutdown(UInt16 timeout)
|
|
{
|
|
//System.Text.StringBuilder sb = new StringBuilder();
|
|
//sb.AppendLine("@echo off");
|
|
//sb.AppendLine("echo System OFF After " + timeout.ToString() + "Seconds");
|
|
//sb.AppendLine("shutdown -s -t " + timeout.ToString());
|
|
//string bfile = AppDomain.CurrentDomain.BaseDirectory + "Shutdown.bat";
|
|
//System.IO.File.WriteAllText(bfile, string.Format(sb.ToString(), AppDomain.CurrentDomain.BaseDirectory), System.Text.Encoding.Default);
|
|
|
|
System.Diagnostics.ProcessStartInfo si = new System.Diagnostics.ProcessStartInfo();
|
|
si.FileName = @"c:\windows\system32\shutdown.exe";
|
|
si.Arguments = "-s -t " + timeout.ToString();
|
|
si.UseShellExecute = false;
|
|
System.Diagnostics.Process prc = new System.Diagnostics.Process();
|
|
prc.StartInfo = si;
|
|
prc.Start();
|
|
}
|
|
|
|
public static void ChangeUIPopup(System.Windows.Forms.NumericUpDown valueCtl)
|
|
{
|
|
var value = valueCtl.Value.ToString();
|
|
var f = UTIL.InputBox("input", value);// new Dialog.fInput(value);
|
|
if (f.Item1)
|
|
{
|
|
var val = decimal.Parse(f.Item2);
|
|
if (val < valueCtl.Minimum)
|
|
{
|
|
UTIL.MsgE(string.Format("최소 입력값은 {0} 입니다.", valueCtl.Minimum));
|
|
val = valueCtl.Minimum;
|
|
}
|
|
if (val > valueCtl.Maximum)
|
|
{
|
|
UTIL.MsgE(string.Format("최대 입력값은 {0} 입니다.", valueCtl.Maximum));
|
|
val = valueCtl.Maximum;
|
|
}
|
|
valueCtl.Value = val;
|
|
}
|
|
|
|
}
|
|
|
|
#region VirtualAGV 실제 데이터 동기화
|
|
public static MapNode FindByNodeID(string nodeidx)
|
|
{
|
|
if (_mapNodes == null || _mapNodes.Any() == false) return null;
|
|
if (nodeidx.isEmpty()) return null;
|
|
return _mapNodes.Where(t => t.NodeId.Equals(nodeidx)).FirstOrDefault();
|
|
}
|
|
public static MapNode FindByRFID(string rfidValue)
|
|
{
|
|
if (_mapNodes == null || _mapNodes.Any() == false) return null;
|
|
if (rfidValue.isEmpty()) return null;
|
|
return _mapNodes.Where(t => t.RfidId.Equals(rfidValue)).FirstOrDefault();
|
|
}
|
|
public static List<MapNode> FindByNodeAlias(string alias)
|
|
{
|
|
if (_mapNodes == null || _mapNodes.Any() == false) return null;
|
|
if (alias.isEmpty()) return null;
|
|
var lst = _mapNodes.Where(t => t.NodeAlias.Equals(alias));
|
|
if (lst.Any() == false) return null;
|
|
return lst.ToList();
|
|
}
|
|
public static List<MapNode> FindByNodeType(AGVNavigationCore.Models.MapNode type)
|
|
{
|
|
if (_mapNodes == null || _mapNodes.Any() == false) return null;
|
|
var lst = _mapNodes.Where(t => t.Type.Equals(type));
|
|
if (lst.Any() == false) return null;
|
|
return lst.ToList();
|
|
}
|
|
/// <summary>
|
|
/// RFID 읽기 시 해당 노드 위치로 AGV 업데이트
|
|
/// </summary>
|
|
/// <param name="rfidId">읽은 RFID ID</param>
|
|
/// <param name="motorDirection">모터 방향 (Forward/Backward)</param>
|
|
/// <returns>업데이트 성공 여부</returns>
|
|
public static bool UpdateAGVFromRFID(string rfidId, AgvDirection motorDirection = AgvDirection.Forward)
|
|
{
|
|
if (_virtualAGV == null || _mapNodes == null) return false;
|
|
|
|
// RFID에 해당하는 노드 찾기
|
|
var node = _mapNodes.FirstOrDefault(n => n.RfidId == rfidId);
|
|
if (node != null)
|
|
{
|
|
_virtualAGV.SetPosition(node, motorDirection);
|
|
RefreshAGVCanvas();
|
|
|
|
log.Add($"[AGV] RFID {rfidId} 감지 → 노드 {node.NodeId} 위치 업데이트 (방향: {motorDirection})");
|
|
return true;
|
|
}
|
|
|
|
log.Add($"[AGV] RFID {rfidId}에 해당하는 노드를 찾을 수 없음");
|
|
return false;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 노드ID로 AGV 위치 업데이트
|
|
/// </summary>
|
|
/// <param name="nodeId">노드 ID</param>
|
|
/// <param name="motorDirection">모터 방향 (Forward/Backward)</param>
|
|
/// <returns>업데이트 성공 여부</returns>
|
|
public static bool UpdateAGVToNode(string nodeId, AgvDirection motorDirection = AgvDirection.Forward)
|
|
{
|
|
if (_virtualAGV == null || _mapNodes == null) return false;
|
|
|
|
var node = _mapNodes.FirstOrDefault(n => n.NodeId == nodeId);
|
|
if (node != null)
|
|
{
|
|
_virtualAGV.SetPosition(node, motorDirection);
|
|
RefreshAGVCanvas();
|
|
|
|
log.Add($"[AGV] 노드 {nodeId} 위치로 이동 (방향: {motorDirection})");
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 모든 로그를 플러시 합니다.
|
|
/// </summary>
|
|
public static void LogFlush()
|
|
{
|
|
PUB.log.Flush();
|
|
PUB.logagv.Flush();
|
|
PUB.logplc.Flush();
|
|
PUB.logbms.Flush();
|
|
PUB.logxbee.Flush();
|
|
}
|
|
|
|
/// <summary>
|
|
/// AGV 방향 업데이트
|
|
/// </summary>
|
|
/// <param name="direction">새로운 방향</param>
|
|
public static void UpdateAGVDirection(AgvDirection direction)
|
|
{
|
|
if (_virtualAGV == null) return;
|
|
|
|
_virtualAGV.CurrentDirection = direction;
|
|
RefreshAGVCanvas();
|
|
}
|
|
|
|
/// <summary>
|
|
/// AGV 상태 업데이트
|
|
/// </summary>
|
|
/// <param name="state">새로운 상태</param>
|
|
public static void UpdateAGVState(AGVState state)
|
|
{
|
|
if (_virtualAGV == null) return;
|
|
|
|
_virtualAGV.CurrentState = state;
|
|
RefreshAGVCanvas();
|
|
}
|
|
|
|
/// <summary>
|
|
/// AGV 배터리 레벨 업데이트
|
|
/// </summary>
|
|
/// <param name="batteryLevel">배터리 레벨 (0.0 ~ 100.0)</param>
|
|
public static void UpdateAGVBattery(float batteryLevel)
|
|
{
|
|
if (_virtualAGV == null) return;
|
|
|
|
_virtualAGV.BatteryLevel = batteryLevel;
|
|
RefreshAGVCanvas();
|
|
}
|
|
|
|
/// <summary>
|
|
/// 맵 캔버스 강제 갱신 (AGV 위치 표시 업데이트)
|
|
/// </summary>
|
|
public static void RefreshAGVCanvas()
|
|
{
|
|
if (_mapCanvas != null && _mapCanvas.IsHandleCreated)
|
|
{
|
|
_mapCanvas.Invalidate();
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 현재 AGV의 노드 ID 가져오기
|
|
/// </summary>
|
|
/// <returns>현재 노드 ID</returns>
|
|
public static string GetCurrentAGVNodeId()
|
|
{
|
|
return _virtualAGV?.CurrentNodeId ?? string.Empty;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 현재 AGV 위치 가져오기
|
|
/// </summary>
|
|
/// <returns>현재 위치</returns>
|
|
public static Point GetCurrentAGVPosition()
|
|
{
|
|
return _virtualAGV?.CurrentPosition ?? Point.Empty;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 현재 AGV 방향 가져오기
|
|
/// </summary>
|
|
/// <returns>현재 방향</returns>
|
|
public static AgvDirection GetCurrentAGVDirection()
|
|
{
|
|
return _virtualAGV?.CurrentDirection ?? AgvDirection.Forward;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 현재 AGV 상태 가져오기
|
|
/// </summary>
|
|
/// <returns>현재 상태</returns>
|
|
public static AGVState GetCurrentAGVState()
|
|
{
|
|
return _virtualAGV?.CurrentState ?? AGVState.Idle;
|
|
}
|
|
|
|
#endregion
|
|
|
|
}
|
|
}
|