2026-01-26 18:56:53 +09:00

664 lines
26 KiB
C#

using Aurora.Api;
using DemoUseDLL.DllSocket_Example;
using Microsoft.Win32;
//using lge.pri.hislog;
using SocketCommDll_4CSharp.LoadControl;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
//using static AuroraCellTracker.CellTrackerObj;
namespace AuroraCellTracker.DaekhonCoporation
{
public class CellTrackerDaekhon : ICellTracker
{
Logger _Logger = new Logger("CellTrackerDaekhon");
private const string REG_PATH = @"Software\H52A\H52A_ADPT_CELL";
public CellInfoStr CellInfoStrings { get; set; } = new CellInfoStr();
public ConcurrentQueue<CellInfoStr> CellInfoQueue { get; set; } = new ConcurrentQueue<CellInfoStr>();
public DllStatus currentDllStatus = new DllStatus();
public DllStatus oldDllStatus = new DllStatus();
#region CellTracker 전/현 상태 관련 클래스
public class DllStatus
{
public bool bIsInitialized;
public bool bIsConnected;
public DllStatus()
{
bIsInitialized = false;
bIsConnected = false;
}
public bool IsDiff(ref DllStatus Input)
{
return ((bIsInitialized != Input.bIsInitialized) || (bIsConnected != Input.bIsConnected));
}
public void CopyFrom(ref DllStatus Input)
{
bIsInitialized = Input.bIsInitialized;
bIsConnected = Input.bIsConnected;
}
}
#endregion
public DllSocketDaekhon dllSocketCtrl;
public static enASCIIBinaryType m_ASCIIType;
private byte[] m_toSendByte = null;
private BinaryTypeStructDaekhon m_BinaryExampleStruct;
public eMode selectedMode = eMode.Callback;
//public string dllDirectory = null;
#region 셀추적 변수
public int CellIdStartNo { get; set; } = 0;
public int CellIdLength { get; set; } = 0;
public int LotIdStartNo { get; set; } = 0;
public int LotIdLength { get; set; } = 0;
#endregion
public static string PreviousLotId { get; set; } = ""; // MP1 CCW의 경우, 용접기 4대가 하나의 Lot ID 정보를 가져야 하기 때문에 static으로 선언
public string OldLotId { get; set; } = "";
public string OldCellId { get; set; } = "";
public void Initialize(eMode mode, string dllDirectory)
{
//Close();
selectedMode = mode;
if (selectedMode == eMode.Queue && dllDirectory != null) {
dllSocketCtrl = new DllSocketDaekhon(dllDirectory, DllSocket_ConnectStatus, null, true);
} else if (selectedMode == eMode.Callback && dllDirectory != null) {
dllSocketCtrl = new DllSocketDaekhon(dllDirectory, DllSocket_ConnectStatus, DllSocket_ReceiveDataBuffer, false);
} else {
dllSocketCtrl = new DllSocketDaekhon(DllSocket_ConnectStatus, null, true);
}
m_BinaryExampleStruct = new BinaryTypeStructDaekhon();
m_BinaryExampleStruct.InitializeBinaryTypeStructExampleStruct();
ClearCellInfo();
CheckDllStatus();
}
public static void SaveString(string keyName, string value)
{
using (RegistryKey key = Registry.CurrentUser.CreateSubKey(REG_PATH)) {
key?.SetValue(keyName, value, RegistryValueKind.String);
}
}
public static string LoadString(string keyName, string defaultValue = "")
{
using (RegistryKey key = Registry.CurrentUser.OpenSubKey(REG_PATH)) {
return key?.GetValue(keyName, defaultValue)?.ToString() ?? defaultValue;
}
}
public void Close()
{
if (null != dllSocketCtrl) {
dllSocketCtrl.DllSocket_Unitialize();
dllSocketCtrl = null;
}
}
public void CheckDllStatus()
{
if (null != dllSocketCtrl) {
if (dllSocketCtrl.DllSocket_IsIntialized()) {
m_ASCIIType = dllSocketCtrl.DllSocket_IsASCIITypeDll() ? enASCIIBinaryType.ASCIITypeDll : enASCIIBinaryType.BinaryTypeDll;
CellInfoStrings.DataType = m_ASCIIType.ToString();
} else {
m_ASCIIType = enASCIIBinaryType.InvalidType;
CellInfoStrings.DataType = m_ASCIIType.ToString();
}
} else {
m_ASCIIType = enASCIIBinaryType.InvalidType;
CellInfoStrings.DataType = m_ASCIIType.ToString();
}
SubDisplayUpdate();
}
public void SetIdComponent(int cellIdStartNo, int cellIdLength, int lotIdStartNo, int lotIdLength)
{
CellIdStartNo = cellIdStartNo;
CellIdLength = cellIdLength;
LotIdStartNo = lotIdStartNo;
LotIdLength = lotIdLength;
}
public CellInfoStr GetCellInfoStrings()
{
return CellInfoStrings;
}
/// <summary>
/// Cell 추적에서 받은 데이터를 보고 Lot ID, Cell ID를 업데이트
/// </summary>
public void ReceiveData()
{
string lotId = "", cellId = "";
if (selectedMode == eMode.Queue) {
if (null != dllSocketCtrl) {
string str = dllSocketCtrl.DllSocket_GetReceiveMessageInQueue(true, true);
if (str.Length > 0) {
CellInfoStrings.ReceiveStrInQueue = str;
CalcCellInfo(str, out lotId, out cellId);
SetCellInfo(lotId, cellId);
} else
CellInfoStrings.ReceiveStrInQueue = "Receive Length is 0";
} else
CellInfoStrings.ReceiveStrInQueue = "Dll Socket Control is NULL";
_Logger.D(string.Format($"{CellInfoStrings.ReceiveStrInQueue}"));
} else if (selectedMode == eMode.Callback) {
// Callback 방식의 경우, 자체 ConcurrentQueue에서 Deque해서 가져와야 함
CellInfoStr info;
if (CellInfoQueue.TryDequeue(out info)) {
SetCellInfo(info.LotID, info.CellID);
}
}
// Queue 방식인데 Cell Tracker에서 메세지가 안 왔거나, Callback 방식인데 Cell Tracker API 함수가 Callback 안 된 경우(ex : ECS 오프라인 모드),
// Lot ID/Cell ID를 ES 지정사양에 맞추어 생성
if (OldLotId == CellInfoStrings.LotID && OldCellId == CellInfoStrings.CellID) {
CalcCellInfo("", out lotId, out cellId);
AddCellInfo(lotId, cellId);
CellInfoStr info;
if (CellInfoQueue.TryDequeue(out info))
{
SetCellInfo(info.LotID, info.CellID);
}
}
OldLotId = CellInfoStrings.LotID;
OldCellId = CellInfoStrings.CellID;
}
public void SendData(string str, bool isSendToUpperSystem = false)
{
switch (m_ASCIIType) {
case enASCIIBinaryType.ASCIITypeDll: {
if (null != dllSocketCtrl) {
dllSocketCtrl.DllSocket_Send(str);
CellInfoStrings.SendStr = str;
}
}
break;
case enASCIIBinaryType.BinaryTypeDll: {
//m_toSendByte = Encoding.Default.GetBytes(str);
m_BinaryExampleStruct.SetString(str);
m_toSendByte = m_BinaryExampleStruct.StCellStructToByte();
if (null != m_toSendByte && null != dllSocketCtrl) {
dllSocketCtrl.DllSocket_Send(m_toSendByte);
CellInfoStrings.SendStr = m_toSendByte.ToString();
}
}
break;
default:
// ! 경고 띄우기
//Trace.WriteLine("Error[Unknown Type] in ReceiveDataBuffer");
break;
}
//if (!isSendToUpperSystem) {
// switch (m_ASCIIType) {
// case enASCIIBinaryType.ASCIITypeDll: {
// if (null != dllSocketCtrl) {
// dllSocketCtrl.DllSocket_Send(str);
// CellInfoStrings.SendStr = str;
// }
// }
// break;
// case enASCIIBinaryType.BinaryTypeDll: {
// //m_toSendByte = Encoding.Default.GetBytes(str);
// m_BinaryExampleStruct.SetString(str);
// m_toSendByte = m_BinaryExampleStruct.StCellStructToByte();
// if (null != m_toSendByte && null != dllSocketCtrl) {
// dllSocketCtrl.DllSocket_Send(m_toSendByte);
// CellInfoStrings.SendStr = m_toSendByte.ToString();
// }
// }
// break;
// default:
// // ! 경고 띄우기
// //Trace.WriteLine("Error[Unknown Type] in ReceiveDataBuffer");
// break;
// }
//} else if (isSendToUpperSystem && null != dllSocketCtrl) {
// string strPath = null, strDate = null, strTime = null, strLotID = null, strCellID = null, strCenterPower = null, strRingPower = null, strDistance = null, strWeldTIme = null;
// SplitLogData(str, ref strPath, ref strDate, ref strTime, ref strLotID, ref strCellID, ref strCenterPower, ref strRingPower, ref strDistance, ref strWeldTIme);
// string strData = string.Format("Date={0},Time={1},LotID={2},CellID={3},LaserCenterPower={4},LaserRingPower={5},WeldingTime={6},Distance={7}",
// strDate, strTime, strLotID, strCellID, strCenterPower, strRingPower, strWeldTIme, strDistance);
// bool bReturn = dllSocketCtrl.DllSocket_AddToECS(strCellID, strPath, strData);
//}
}
public List<string> SendData(string str, ref string strPath)
{
return new List<string>();
}
public void SendEcsData(string strCellID, string strPath, string strData)
{
if (dllSocketCtrl != null) {
bool bReturn = dllSocketCtrl.DllSocket_AddToECS(strCellID, strPath, strData);
}
}
public void SetIPConfig()
{
if (dllSocketCtrl != null) {
dllSocketCtrl.DllSocket_IPConfigToggleShow(true, false);
}
}
#region ConnectStatus, ReceiveBuffer, Display 관련
private void DllSocket_ConnectStatus(string strEventContents, int nStatus, int nErrorCode)
{
CellInfoStrings.EventContentStr = strEventContents;
CellInfoStrings.StatusStr = nStatus.ToString();
CellInfoStrings.ErrorCodeStr = nErrorCode.ToString();
//Debug.WriteLine(CellInfoStrings.EventContentStr + CellInfoStrings.StatusStr + CellInfoStrings.ErrorCodeStr);
//if (LABEL_DLL_CONNECTED.InvokeRequired)
//{
// // 작업쓰레드인 경우
// LABEL_DLL_CONNECTED.BeginInvoke(
// new Action(() => LABEL_DLL_CONNECTED.Text = string.Format("{0} :{1}, {2}", strEventContents, nStatus, nErrorCode)));
//}
//else
//{
// // UI 쓰레드인 경우
// LABEL_DLL_CONNECTED.Text = string.Format("{0} :{1}, {2}", strEventContents, nStatus, nErrorCode);
//}
}
/// <summary>
/// Callback 방식일 때, API에서 자동으로 호출되는 함수
/// </summary>
/// <param name="ReceiveBuffer"></param>
private void DllSocket_ReceiveDataBuffer(byte[] ReceiveBuffer)
{
switch (m_ASCIIType) {
case enASCIIBinaryType.ASCIITypeDll:
if (null != ReceiveBuffer && ReceiveBuffer.Length > 0) {
try {
string str = Encoding.ASCII.GetString(ReceiveBuffer);
CellInfoStrings.ReceiveBufferStr = str;
_Logger.I(string.Format($"ASCII {CellInfoStrings.ReceiveBufferStr}"));
string lotId, cellId;
CalcCellInfo(str, out lotId, out cellId);
AddCellInfo(lotId, cellId);
} catch (Exception e) {
_Logger.E(string.Format($"{e.Message}"));
}
}
break;
case enASCIIBinaryType.BinaryTypeDll:
if (null != ReceiveBuffer && ReceiveBuffer.Length > 0) {
try {
string str = Encoding.Default.GetString(ReceiveBuffer);
//string str = BitConverter.ToString(ReceiveBuffer);
CellInfoStrings.ReceiveBufferStr = str;
string lotId, cellId;
cellId = str.Substring(41, 24); // 글자 수 증가
lotId = str.Substring(11, 16);
_Logger.I(string.Format($"Binary CELLID: {cellId} LotID: {lotId}"));
//CalcCellInfo(str, out lotId, out cellId);
AddCellInfo(lotId, cellId);
} catch (Exception e) {
_Logger.E(string.Format($"{e.Message}"));
}
}
break;
}
}
private void SubDisplayUpdate()
{
if (null != dllSocketCtrl) {
currentDllStatus.bIsInitialized = dllSocketCtrl.DllSocket_IsIntialized();
} else {
currentDllStatus.bIsInitialized = false;
currentDllStatus.bIsConnected = false;
}
if (oldDllStatus.IsDiff(ref currentDllStatus)) {
if (currentDllStatus.bIsConnected != oldDllStatus.bIsConnected) {
if (currentDllStatus.bIsConnected) {
CellInfoStrings.ConnectedStatusStr = "Connected";
} else {
CellInfoStrings.ConnectedStatusStr = "Disconnected";
}
}
if (currentDllStatus.bIsInitialized != oldDllStatus.bIsInitialized) {
if (currentDllStatus.bIsInitialized) {
CellInfoStrings.InitializedStatusStr = "OK";
} else {
CellInfoStrings.InitializedStatusStr = "NO";
}
}
oldDllStatus.CopyFrom(ref currentDllStatus);
}
}
#endregion
#region LotID/Cell ID 문자열 추줄
/// <summary>
/// Cell ID를 못 받은 경우, 장비에서 Cell ID를 임의로 생성해야 한다. 그 생성의 기준이 되는 Index
/// </summary>
private static int m_nCellI_NULL_Index = 0;
/// <summary>
/// Cell 추적 API에서 받은 문자열에서, Cell ID와 Lot ID를 Parsing 하는 함수
/// </summary>
/// <param name="str">Cell 추적 API에서 받은 문자열. Callback 방식일 때와 Queue 방식일 때 각각 다르다</param>
private void CalcCellInfo(string str, out string lotId, out string cellId)
{
lotId = cellId = "";
try {
string strCellID = "";
string strLotID = "";
if (!string.IsNullOrWhiteSpace(str)) {
if (selectedMode == eMode.Callback) {
strCellID = str.Substring(CellIdStartNo, CellIdLength);
strLotID = str.Substring(LotIdStartNo, LotIdLength);
} else if (selectedMode == eMode.Queue) {
int nIndex = 0;
string[] strArr1 = str.Split(',');
for (int i = 0; i < strArr1.Length; i++) {
string strWord = strArr1[nIndex++];
if (strWord.Contains("CellID") == true) {
string[] strArr2 = strWord.Split('=');
strCellID = strArr2[1];
}
if (strWord.Contains("LotID") == true) {
string[] strArr2 = strWord.Split('=');
strLotID = strArr2[1];
}
}
}
// Cell ID, Lot ID 공백 및 NUL 제거 필요 : 공백 및 NUL 있을 시, API Log 인식 잘 못 됨.
strCellID = strCellID.Replace(" ", "");
strCellID = strCellID.Replace("\0", "");
strLotID = strLotID.Replace(" ", "");
strLotID = strLotID.Replace("\0", "");
}
if (string.IsNullOrWhiteSpace(strLotID)) {
if (PreviousLotId.Contains('-')) // 이미 임시 Lot ID인 상태(업데이트 할 필요 없음)
{
lotId = PreviousLotId;
} else {
m_nCellI_NULL_Index = 0;
strLotID = DateTime.Now.ToString("yyyyMMdd-HHmmss");
lotId = strLotID;
PreviousLotId = lotId;
}
} else {
lotId = strLotID;
PreviousLotId = lotId;
}
if (string.IsNullOrWhiteSpace(strCellID)) {
m_nCellI_NULL_Index++;
strCellID = "CELL" + m_nCellI_NULL_Index.ToString("D7"); // 7자리로 표시(ex : CELL0000001, CELL0000002, ...)
cellId = strCellID;
} else {
m_nCellI_NULL_Index = 0;
cellId = strCellID;
}
} catch (Exception e) {
_Logger.E(string.Format($"{e.Message}"));
}
}
private void ClearCellInfo()
{
CellInfoStrings.LotID = "";
CellInfoStrings.CellID = "";
PreviousLotId = "";
OldLotId = "";
OldCellId = "";
if (CellInfoQueue == null) return;
while (!CellInfoQueue.IsEmpty) {
CellInfoStr temp;
CellInfoQueue.TryDequeue(out temp);
}
}
private void AddCellInfo(string lotId, string cellId)
{
if (CellInfoQueue == null) return;
CellInfoStr info = new CellInfoStr();
info.LotID = lotId;
info.CellID = cellId;
//Callback 방식이라고하지만 내부에서는 Queue 방식으로 진행됨. Queue가 쌓여있으면 문제가 되므로 받을때마다 Clear 하는 부분 추가.
//ClearCellInfo();
CellInfoQueue.Enqueue(info);
_Logger.D(string.Format($"NEW Lot ID : {lotId}"));
_Logger.D(string.Format($"NEW CELL ID : {cellId} "));
}
public void SetCellInfo(string lotId, string cellId)
{
lotId = lotId.Replace("\0", "");
cellId = cellId.Replace("\0", "");
CellInfoStrings.LotID = lotId.Trim();
CellInfoStrings.CellID = cellId.Trim();
_Logger.D(string.Format($"Dequeue Lot ID : {lotId}"));
_Logger.D(string.Format($"Dequeue CELL ID : {cellId}"));
}
#endregion
}
struct BinaryTypeStructDaekhon
{
/// <summary>
/// 셀 id 10개 문자열
/// </summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)]
public char[] Char_CellID;
[MarshalAs(UnmanagedType.I4)] //4
public Int32 intCount;
//바이트 배열
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 170)]
public byte[] byteTest;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]//16
public UInt32[] uintTest;
/// <summary>
/// StCellID Struct 구조체 전체를 초기화 하는 함수
/// </summary>
public void InitializeBinaryTypeStructExampleStruct()
{
if (null == Char_CellID) {
byte[] temp = new byte[Marshal.SizeOf(typeof(BinaryTypeStructDaekhon))];
this = (BinaryTypeStructDaekhon)ByteToStCellStruct(temp);
}
intCount = 0;
Array.Clear(byteTest, 0, byteTest.Length);
Array.Clear(uintTest, 0, uintTest.Length);
Array.Clear(Char_CellID, 0, Char_CellID.Length);
}
/// <summary>
/// 구조체를 배열로 바꾸는 부분
/// </summary>
/// <returns></returns>
public byte[] StCellStructToByte()
{
try {
byte[] buffer = new byte[Marshal.SizeOf(typeof(BinaryTypeStructDaekhon))];
GCHandle gch = GCHandle.Alloc(buffer, GCHandleType.Pinned);
//구조체를 바꾸는 부분
Marshal.StructureToPtr(this, gch.AddrOfPinnedObject(), false);
gch.Free();
return buffer;
} catch (Exception exc) {
Trace.WriteLine($"Error[{exc.Message}] in StCellStructToByte");
}
return null;
}
public object IntptrToBinaryTypeStructExample(IntPtr p, int nbyteSize)
{
try {
int nSize = Marshal.SizeOf(typeof(BinaryTypeStructDaekhon));
if (nbyteSize == nSize) {
if (Marshal.SizeOf(this) != nSize) {
InitializeBinaryTypeStructExampleStruct();
}
if (Marshal.SizeOf(this) == nSize) {
Marshal.StructureToPtr(this, p, false);
return this;
}
}
} catch (Exception exc) {
Trace.WriteLine($"Error[{exc.Message}] in IntptrToBinaryTypeStructExample");
}
return null;
}
/// <summary>
/// 배열을 구조체로
/// </summary>
/// <param name="data"></param>
/// <param name="dataType"></param>
/// <returns></returns>
public object ByteToStCellStruct(byte[] data)
{
try {
Type nType = typeof(BinaryTypeStructDaekhon);
int RawSize = Marshal.SizeOf(nType);
//만약에 데이터가 없으면 리턴값은 null값에 취한다.
if (RawSize > data.Length) {
return null;
}
IntPtr buffer = Marshal.AllocHGlobal(RawSize);
Marshal.Copy(data, 0, buffer, RawSize);
object objData = Marshal.PtrToStructure(buffer, nType);
Marshal.FreeHGlobal(buffer);
return objData;
} catch (Exception exc) {
Trace.WriteLine($"Error[{exc.Message}] in ByteToStCellStruct");
}
return null;
}
/// <summary>
/// 배열에서 자기 구조체로 처리
/// </summary>
/// <param name="data"></param>
public void SelfStructFromByte(byte[] data)
{
try {
this = (BinaryTypeStructDaekhon)ByteToStCellStruct(data);
} catch (Exception exc) {
Trace.WriteLine($"Error[{exc.Message}] in SelfStructFromByte");
}
return;
}
public override bool Equals(object obj)
{
try {
if (GetHashCode() == obj.GetHashCode()) {
BinaryTypeStructDaekhon b = (BinaryTypeStructDaekhon)obj;
return b.Char_CellID == this.Char_CellID && byteTest.SequenceEqual(b.byteTest) && uintTest.SequenceEqual(b.uintTest) && intCount == b.intCount;
}
} catch (Exception exc) {
Trace.WriteLine($"Error[{exc.Message}] in Equals");
}
return false;
}
/// <summary>
/// StCellID 해쉬코드 반환
/// </summary>
/// <returns></returns>
public override int GetHashCode()
{
return Char_CellID.GetHashCode() + intCount.GetHashCode() + byteTest.GetHashCode() + uintTest.GetHashCode();
}
public void SetString(string strCellID)
{
try {
if (strCellID.Length > 0) {
byte[] StrByte = Encoding.UTF8.GetBytes(strCellID);
Array.Copy(StrByte, Char_CellID, 10);
}
} catch (Exception exc) {
Trace.WriteLine($"Error[{exc.Message}] in SetString");
}
}
/// <summary>
/// 문자열로 반환
/// </summary>
/// <returns></returns>
public override string ToString()
{
try {
return new string(Char_CellID).TrimEnd('\r', '\n', '\0');
} catch (Exception exc) {
Trace.WriteLine($"Error[{exc.Message}] in ToString");
}
return "";
}
///////////////////////////////////////////////////
}
}