Files
ENIG/Cs_HMI/Project/PUB.cs
backuppc a7f938ff19 ..
2025-12-15 17:34:43 +09:00

758 lines
28 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>
/// 다음 작업 명령 (PickOn/PickOff)
/// </summary>
public static ENIGProtocol.AGVCommandHE NextWorkCmd = ENIGProtocol.AGVCommandHE.Stop;
/// <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)
{
var _mapNodes = PUB._mapCanvas.Nodes;
if (_mapNodes == null || _mapNodes.Any() == false) return null;
if (nodeidx.isEmpty()) return null;
return _mapNodes.Where(t => t.Id.Equals(nodeidx)).FirstOrDefault();
}
public static MapNode FindByRFID(string rfidValue)
{
var _mapNodes = PUB._mapCanvas.Nodes;
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)
{
var _mapNodes = PUB._mapCanvas.Nodes;
if (_mapNodes == null || _mapNodes.Any() == false) return null;
if (alias.isEmpty()) return null;
var lst = _mapNodes.Where(t => t.AliasName.Equals(alias));
if (lst.Any() == false) return null;
return lst.ToList();
}
public static List<MapNode> FindByNodeType(AGVNavigationCore.Models.MapNode type)
{
var _mapNodes = PUB._mapCanvas.Nodes;
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(ushort rfidId, AgvDirection motorDirection = AgvDirection.Forward)
{
var _mapNodes = PUB._mapCanvas.Nodes;
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.Id} 위치 업데이트 (방향: {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)
{
var _mapNodes = PUB._mapCanvas.Nodes;
if (_virtualAGV == null || _mapNodes == null) return false;
var node = _mapNodes.FirstOrDefault(n => n.Id == 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.SetBatteryLevel(batteryLevel);
RefreshAGVCanvas();
}
/// <summary>
/// 맵 캔버스 강제 갱신 (AGV 위치 표시 업데이트)
/// </summary>
public static void RefreshAGVCanvas()
{
if (_mapCanvas != null && _mapCanvas.IsHandleCreated)
{
_mapCanvas.Invalidate();
}
}
#endregion
}
}