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 event Action OnCellReceived; public CellInfoStr CellInfoStrings { get; set; } = new CellInfoStr(); public ConcurrentQueue CellInfoQueue { get; set; } = new ConcurrentQueue(); 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; } /// /// Cell 추적에서 받은 데이터를 보고 Lot ID, Cell ID를 업데이트 /// public void ReceiveData() { string lotId = "", cellId = ""; bool gotNew = false; 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); gotNew = true; } 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); gotNew = true; } } // Queue 방식인데 Cell Tracker에서 메세지가 안 왔거나, // Callback 방식인데 실제 수신이 없거나(또는 같은 값이 연속으로 들어오는 경우), // Lot ID/Cell ID를 ES 지정사양에 맞추어 생성 if (!gotNew || (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); } else { // 새로운 값이 안들어와도 일단 보여줌 SetCellInfo(lotId, cellId); } } OldLotId = CellInfoStrings.LotID; OldCellId = CellInfoStrings.CellID; _Logger.I($"Received CellInfo >> count({CellInfoQueue.Count})"); } 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 SendData(string str, ref string strPath) { return new List(); } 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); //} } /// /// Callback 방식일 때, API에서 자동으로 호출되는 함수 /// /// 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); OnCellReceived?.Invoke(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); // CellTracker Config에서 입력 된 값을 가져와 설정한다. cellId = str.Substring(CellIdStartNo, CellIdLength).Trim('\0'); lotId = str.Substring(LotIdStartNo, LotIdLength).Trim('\0'); _Logger.I(string.Format($"Binary CELLID: {cellId} LotID: {lotId}")); //CalcCellInfo(str, out lotId, out cellId); AddCellInfo(lotId, cellId); OnCellReceived?.Invoke(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 문자열 추줄 /// /// Cell ID를 못 받은 경우, 장비에서 Cell ID를 임의로 생성해야 한다. 그 생성의 기준이 되는 Index /// private static int m_nCellI_NULL_Index = 0; /// /// Cell 추적 API에서 받은 문자열에서, Cell ID와 Lot ID를 Parsing 하는 함수 /// /// Cell 추적 API에서 받은 문자열. Callback 방식일 때와 Queue 방식일 때 각각 다르다 public 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 { /// /// 셀 id 10개 문자열 /// [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; /// /// StCellID Struct 구조체 전체를 초기화 하는 함수 /// 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); } /// /// 구조체를 배열로 바꾸는 부분 /// /// 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; } /// /// 배열을 구조체로 /// /// /// /// 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; } /// /// 배열에서 자기 구조체로 처리 /// /// 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; } /// /// StCellID 해쉬코드 반환 /// /// 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"); } } /// /// 문자열로 반환 /// /// 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 ""; } /////////////////////////////////////////////////// } }