using System; using System.Threading; namespace SA_LTT.Module { public class PreAligner : ComPort { public enum ErrorCode { None, PinUpError, PinDownError, VaccumError, NoWafer, WaferLimitErrorAfterAlign, NotFoundNotch, StageLimitError = 9, InvalidAlignCommand, ChuckArrangeError, WaferAlignCCDOver, WaferLimitErrorBeforeAlign, RetractHome = 16, WaferExist, CCDModuleError = 30, AlignerTypeError = 50, CommandError = 999, } private Equipment _equipment; private Thread t_statusUpdate; private Thread t_commandWriteRead; private string _version; private double _positionX; private double _positionY; private double _positionT; private bool _isWaferExist; private bool _isVacuumOn; private bool _isHome; private bool _isAlignRun; private bool _lockCheck; private object _thisLock = new object(); private int waitTime = 100; public ErrorCode error; private SequenceTimer _timer = new SequenceTimer(); public string Version { get { return _version; } set { _version = value; } } public double PositionX { get { return _positionX; } set { _positionX = value; } } public double PositionY { get { return _positionY; } set { _positionY = value; } } public double PositionT { get { return _positionT; } set { _positionT = value; } } public bool IsHome { get { return _isHome; } set { _isHome = value; } } public bool IsWaferExist { get { return _isWaferExist; } set { _isWaferExist = value; } } public bool IsVacuumOn { get { return _isVacuumOn; } set { _isVacuumOn = value; } } public bool IsAlignRun { get { return _isAlignRun; } set { _isAlignRun = value; } } public bool IsRunEnable { get { if(IsOpen && (t_commandWriteRead == null || t_commandWriteRead.ThreadState == ThreadState.Stopped)) { return true; } else { return false; } } } public PreAligner(Equipment equipment) { serialPort.PortName = "COM4"; serialPort.DataBits = 8; serialPort.Parity = System.IO.Ports.Parity.None; serialPort.StopBits = System.IO.Ports.StopBits.One; serialPort.BaudRate = 19200; ReceiveWaitSeconds = 0.1; Terminator = null; _equipment = equipment; error = ErrorCode.None; t_statusUpdate = new Thread(statusUpdate); t_statusUpdate.Start(); } public void statusUpdate() { while (_equipment.IsDisposed == false) { try { Thread.Sleep(waitTime); if (IsOpen) { if (IsRunEnable) { ReadPosition(); ReadStatus(); } } else { if (_equipment.alarmManager.OccurredAlarms.Exists(x => x.Code == AlarmCode.AL_0051_PRE_ALIGNER_DISCONNECTED)) { } else { if (Open() == false) { _equipment.alarmManager.Occur(AlarmCode.AL_0051_PRE_ALIGNER_DISCONNECTED); } else { if (ReadVersion() == false) { Close(); } else { //Home(); } } } } } catch (Exception e) { EquipmentLogManager.Instance.WriteExceptionLog(e.StackTrace); } } } public void Align(double angle) { if (IsRunEnable == false) return; t_commandWriteRead = new Thread(() => { lock (_thisLock) { while (_lockCheck) Monitor.Wait(_thisLock); try { _lockCheck = true; IsAlignRun = true; if (angle < 0) { angle = 0; } else if (angle > 359.999) { angle = 359.999; } string str = WriteRead($"ALIGN {angle:f3}"); string str1 = Read(10); //ALIGN 90.000\rEND\r string[] datas = str.Split('\r'); if (datas.Length == 3 && datas[1].Contains("ERR")) { string errorCode = datas[1].Split(' ')[1]; error = (ErrorCode)Enum.Parse(typeof(ErrorCode), errorCode); SetAlarmCode(error); } datas = str1.Split('\r'); if (datas.Length == 3 && datas[1].Contains("ERR")) { string errorCode = datas[1].Split(' ')[1]; error = (ErrorCode)Enum.Parse(typeof(ErrorCode), errorCode); SetAlarmCode(error); } Thread.Sleep(100); string log = WriteRead($"RQ POSITION"); EquipmentLogManager.Instance.WritePreAlignLog("Result : " + log.Replace('\r', ' ')); Thread.Sleep(waitTime); } catch (Exception e) { EquipmentLogManager.Instance.WriteExceptionLog(e.StackTrace); } finally { IsAlignRun = false; _lockCheck = false; Monitor.Pulse(_thisLock); } } } ); t_commandWriteRead.Start(); } /// /// 얼라인 이후에 각도 변경 /// /// public void Again(double angle) { if (IsRunEnable == false) return; t_commandWriteRead = new Thread(() => { lock (_thisLock) { while (_lockCheck) Monitor.Wait(_thisLock); try { _lockCheck = true; IsAlignRun = true; if (angle < 0) { angle = 0; } else if (angle > 359.999) { angle = 359.999; } string str = WriteRead($"AGAIN {angle:f3}"); string[] datas = str.Split('\r'); if (datas.Length == 3 && datas[1].Contains("ERR")) { error = (ErrorCode)Enum.Parse(typeof(ErrorCode), datas[1].Split(' ')[1]); SetAlarmCode(error); } Thread.Sleep(waitTime); //AGAIN 0.000\rEND\r } catch (Exception e) { EquipmentLogManager.Instance.WriteExceptionLog(e.StackTrace); } finally { IsAlignRun = false; _lockCheck = false; Monitor.Pulse(_thisLock); } } }); t_commandWriteRead.Start(); } public bool ReadVersion() { lock (_thisLock) { while (_lockCheck) Monitor.Wait(_thisLock); try { _lockCheck = true; string receivedData = WriteRead($"VER"); string[] datas = receivedData.Split('\r'); if (datas.Length == 3) { Version = datas[1]; return true; } else { return false; } } catch (Exception e) { EquipmentLogManager.Instance.WriteExceptionLog(e.StackTrace); return false; } finally { _lockCheck = false; Monitor.Pulse(_thisLock); } } } public void Home() { if (IsRunEnable == false) return; t_commandWriteRead = new Thread(() => { lock (_thisLock) { while (_lockCheck) Monitor.Wait(_thisLock); try { _lockCheck = true; string str = WriteRead($"HOME"); str = Read(20); //HOME\rEND\r Thread.Sleep(waitTime); } catch (Exception e) { EquipmentLogManager.Instance.WriteExceptionLog(e.StackTrace); } finally { _lockCheck = false; Monitor.Pulse(_thisLock); } } }); t_commandWriteRead.Start(); } public void VacuumOn() { if (IsRunEnable == false) return; t_commandWriteRead = new Thread(() => { lock (_thisLock) { while (_lockCheck) Monitor.Wait(_thisLock); try { _lockCheck = true; string str = WriteRead($"VAC ON"); str = Read(5); string[] datas = str.Split('\r'); if (datas.Length == 3 && datas[1].Contains("ERR")) { error = (ErrorCode)Enum.Parse(typeof(ErrorCode), datas[1].Split(' ')[1]); SetAlarmCode(error); } Thread.Sleep(waitTime); } catch (Exception e) { EquipmentLogManager.Instance.WriteExceptionLog(e.StackTrace); } finally { _lockCheck = false; Monitor.Pulse(_thisLock); } } }); t_commandWriteRead.Start(); } public void VacuumOff() { if (IsRunEnable == false) return; t_commandWriteRead = new Thread(() => { lock (_thisLock) { while (_lockCheck) Monitor.Wait(_thisLock); try { _lockCheck = true; string str = WriteRead($"VAC OFF"); string[] datas = str.Split('\r'); if (datas.Length == 3 && datas[1].Contains("ERR")) { error = (ErrorCode)Enum.Parse(typeof(ErrorCode), datas[1].Split(' ')[1]); SetAlarmCode(error); } Thread.Sleep(waitTime); } catch (Exception e) { EquipmentLogManager.Instance.WriteExceptionLog(e.StackTrace); } finally { _lockCheck = false; Monitor.Pulse(_thisLock); } } }); t_commandWriteRead.Start(); } public void PinUp() { if (IsRunEnable == false) return; t_commandWriteRead = new Thread(() => { t_commandWriteRead.Start(); lock (_thisLock) { while (_lockCheck) Monitor.Wait(_thisLock); try { _lockCheck = true; string str = WriteRead($"PIN UP"); //PIN UP\r Thread.Sleep(waitTime); } catch (Exception e) { EquipmentLogManager.Instance.WriteExceptionLog(e.StackTrace); } finally { _lockCheck = false; Monitor.Pulse(_thisLock); } } }); } public void PinDown() { if (IsRunEnable == false) return; t_commandWriteRead = new Thread(() => { lock (_thisLock) { while (_lockCheck) Monitor.Wait(_thisLock); try { _lockCheck = true; string str = WriteRead($"PIN DN"); //PIN DN\r Thread.Sleep(waitTime); } catch (Exception e) { EquipmentLogManager.Instance.WriteExceptionLog(e.StackTrace); } finally { _lockCheck = false; Monitor.Pulse(_thisLock); } } }); t_commandWriteRead.Start(); } public void ReadStatus() { lock (_thisLock) { while (_lockCheck) Monitor.Wait(_thisLock); try { _lockCheck = true; string str = WriteRead($"STATUS"); //STATUS\r[0:ON 1:OFF] VAC:1 WF1:1 WF2:0 START:1 CLR:1 HOME:1 IN4:1 RUN:1 WAF:0 VAC:1 ALM:0\r string[] datas = str.Split('\r'); if(datas.Length == 3) { string[] status = datas[1].Split(' '); IsHome = status[7].Split(':')[1] == "0" ? true : false; IsWaferExist = status[10].Split(':')[1] == "0" ? true : false; IsVacuumOn = status[11].Split(':')[1] == "0" ? true : false; } Thread.Sleep(waitTime); } catch (Exception e) { EquipmentLogManager.Instance.WriteExceptionLog(e.StackTrace); } finally { _lockCheck = false; Monitor.Pulse(_thisLock); } } } public void ReadLog() { string str = WriteRead($"RQ LOG"); } public void ReadAlarmCode() { if (IsRunEnable == false) return; t_commandWriteRead = new Thread(() => { }); t_commandWriteRead.Start(); lock (_thisLock) { while (_lockCheck) Monitor.Wait(_thisLock); try { _lockCheck = true; string str = WriteRead($"ALARM CODE"); str = Read(20); //ALARM CODE\rNO_ALARM\r Thread.Sleep(waitTime); } catch (Exception e) { EquipmentLogManager.Instance.WriteExceptionLog(e.StackTrace); } finally { _lockCheck = false; Monitor.Pulse(_thisLock); } } } public void ReadPinStatus() { if (IsRunEnable == false) return; t_commandWriteRead = new Thread(() => { }); t_commandWriteRead.Start(); lock (_thisLock) { while (_lockCheck) Monitor.Wait(_thisLock); try { _lockCheck = true; string str = WriteRead($"RQ PIN"); //RQ PIN\r Thread.Sleep(waitTime); } catch (Exception e) { EquipmentLogManager.Instance.WriteExceptionLog(e.StackTrace); } finally { _lockCheck = false; Monitor.Pulse(_thisLock); } } } public void ReadWaferStatus() { if (IsRunEnable == false) return; t_commandWriteRead = new Thread(() => { }); t_commandWriteRead.Start(); lock (_thisLock) { while (_lockCheck) Monitor.Wait(_thisLock); try { _lockCheck = true; string str = WriteRead($"RQ WAFER"); //RQ WAFER\r Thread.Sleep(waitTime); } catch (Exception e) { EquipmentLogManager.Instance.WriteExceptionLog(e.StackTrace); } finally { _lockCheck = false; Monitor.Pulse(_thisLock); } } } public void ReadVaccumStatus() { if (IsRunEnable == false) return; t_commandWriteRead = new Thread(() => { }); t_commandWriteRead.Start(); lock (_thisLock) { while (_lockCheck) Monitor.Wait(_thisLock); try { _lockCheck = true; string str = WriteRead($"RQ VAC"); //RQ VAC\r[OFF]\r Thread.Sleep(waitTime); } catch (Exception e) { EquipmentLogManager.Instance.WriteExceptionLog(e.StackTrace); } finally { _lockCheck = false; Monitor.Pulse(_thisLock); } } } public void ReadParameter() { lock (_thisLock) { while (_lockCheck) Monitor.Wait(_thisLock); try { _lockCheck = true; string str = WriteRead($"RQ PARA"); str = Read(3); //"RQ PARA\r\rVER 1.2(DX)-01\rTYPE 1\rDEEP 0.6\rDEEX 1.5\rRETRY 5\rSET 000.00\rOFFSET +000.000\rWIDTH 5\rWAFER SIZE 300\rBASE LENGTH 142\rLOOP 1\rRESET 1\rLOG 1\rVAC KEEP 0\rRESPONSE 1\rWP 0\rDIST" Thread.Sleep(waitTime); } catch (Exception e) { EquipmentLogManager.Instance.WriteExceptionLog(e.StackTrace); } finally { _lockCheck = false; Monitor.Pulse(_thisLock); } } } public void ReadPosition() { lock (_thisLock) { while (_lockCheck) Monitor.Wait(_thisLock); try { _lockCheck = true; string receivedData = WriteRead("RQ POSITION"); string[] datas = receivedData.Split('\r'); if (datas.Length == 3) { string[] positions = datas[1].Split(' '); PositionX = double.Parse(positions[1]); PositionY = double.Parse(positions[2]); PositionT = double.Parse(positions[3]); } else { } Thread.Sleep(waitTime); } catch (Exception e) { EquipmentLogManager.Instance.WriteExceptionLog(e.StackTrace); } finally { _lockCheck = false; Monitor.Pulse(_thisLock); } } } public void Center() { if (IsRunEnable == false) return; t_commandWriteRead = new Thread(() => { lock (_thisLock) { while (_lockCheck) Monitor.Wait(_thisLock); try { _lockCheck = true; string str = WriteRead($"CENTER"); string[] datas = str.Split('\r'); if (datas.Length == 3 && datas[1].Contains("ERR")) { error = (ErrorCode)Enum.Parse(typeof(ErrorCode), datas[1].Split(' ')[1]); SetAlarmCode(error); } Thread.Sleep(waitTime); } catch (Exception e) { EquipmentLogManager.Instance.WriteExceptionLog(e.StackTrace); } finally { _lockCheck = false; Monitor.Pulse(_thisLock); } } }); t_commandWriteRead.Start(); } public void SetAlignOffset(double offset) { lock (_thisLock) { while (_lockCheck) Monitor.Wait(_thisLock); try { _lockCheck = true; string str = WriteRead($"OFFSET {offset:3f}"); Thread.Sleep(waitTime); } catch (Exception e) { EquipmentLogManager.Instance.WriteExceptionLog(e.StackTrace); } finally { _lockCheck = false; Monitor.Pulse(_thisLock); } } } //=================================================================== public new bool Write(string command) { string data = base.WriteRead(command + "\r"); if (data != string.Empty) { return true; } else { return false; } } public new string WriteRead(string command) { string receivedData = string.Empty; receivedData = base.WriteRead(command + "\r"); if (receivedData.StartsWith(command.Split(' ')[0])) { return receivedData; } else { if (receivedData.Contains("ERR")) { string errorCode = receivedData.Split(' ')[1].Replace("\r", ""); if (Enum.TryParse(errorCode, out error)) { SetAlarmCode(error); } //Error 추가. } return "-1"; } } public bool WriteRead(string command, out string receivedData) { string data = base.WriteRead(command + '\r'); if (data.StartsWith(command.Split(' ')[0])) { receivedData = data.Remove(0, command.Split(' ')[0].Length).Replace("\r", ""); return true; } else { receivedData = string.Empty; return false; } } private void SetAlarmCode(ErrorCode errorCode) { EquipmentLogManager.Instance.WritePreAlignLog($"Error Code : {(int)errorCode} : {errorCode.ToString()}"); switch (errorCode) { case ErrorCode.PinUpError: { _equipment.alarmManager.Occur(AlarmCode.AL_0500_PREALIGNER_PIN_UP_ERROR); break; } case ErrorCode.PinDownError: { _equipment.alarmManager.Occur(AlarmCode.AL_0501_PREALIGNER_PIN_DOWN_ERROR); break; } case ErrorCode.VaccumError: { _equipment.alarmManager.Occur(AlarmCode.AL_0502_PREALIGNER_VACCUM_ERROR); break; } case ErrorCode.NoWafer: { _equipment.alarmManager.Occur(AlarmCode.AL_0503_PREALIGNER_NO_WAFER); break; } case ErrorCode.WaferLimitErrorAfterAlign: { _equipment.alarmManager.Occur(AlarmCode.AL_0504_PREALIGNER_WAFER_LIMIT_ERROR_AFTER_ALIGN); break; } case ErrorCode.NotFoundNotch: { _equipment.alarmManager.Occur(AlarmCode.AL_0505_PREALIGNER_NOT_FOUND_NOTCH); break; } case ErrorCode.StageLimitError: { _equipment.alarmManager.Occur(AlarmCode.AL_0506_PREALIGNER_STAGE_LIMIT_ERROR); break; } case ErrorCode.InvalidAlignCommand: { _equipment.alarmManager.Occur(AlarmCode.AL_0507_PREALIGNER_INVALID_ALIGN_COMMAND); break; } case ErrorCode.ChuckArrangeError: { _equipment.alarmManager.Occur(AlarmCode.AL_0508_PREALIGNER_CHUCK_ARRANGE_ERROR); break; } case ErrorCode.WaferAlignCCDOver: { _equipment.alarmManager.Occur(AlarmCode.AL_0509_PREALIGNER_WAFER_ALIGN_CCD_OVER); break; } case ErrorCode.WaferLimitErrorBeforeAlign: { _equipment.alarmManager.Occur(AlarmCode.AL_0510_PREALIGNER_WAFER_LIMIT_ERROR_BEFORE_ALIGN); break; } case ErrorCode.RetractHome: { _equipment.alarmManager.Occur(AlarmCode.AL_0511_PREALIGNER_RETRACT_HOME); break; } case ErrorCode.WaferExist: { _equipment.alarmManager.Occur(AlarmCode.AL_0512_PREALIGNER_WAFER_EXIST); break; } case ErrorCode.CCDModuleError: { _equipment.alarmManager.Occur(AlarmCode.AL_0513_PREALIGNER_CCD_MODULE_ERROR); break; } case ErrorCode.AlignerTypeError: { _equipment.alarmManager.Occur(AlarmCode.AL_0514_PREALIGNER_ALIGNER_TYPE_ERROR); break; } case ErrorCode.CommandError: { _equipment.alarmManager.Occur(AlarmCode.AL_0515_PREALIGNER_COMMAND_ERROR); break; } } } } }