using SA_LTT.Info.WaferInfo;
|
using System;
|
using System.Collections;
|
using System.Text;
|
using System.Threading;
|
using static SA_LTT.Info.WaferInfo.WaferInfoManager;
|
|
namespace SA_LTT.Module
|
{
|
/*
|
======== Movement ======================
|
Wafer Handling -> Get Ready Get Put Ready Put
|
Arm Motion -> Extend arm, Retract arm // 팬던트에서만 하도록.
|
Cross Motion -> Dual arm WTR 로봇일 때 // 안하는걸로
|
Mapping -> Mapping motion test, Mapping Calibration, Mapping setting, Mapping
|
Deflection check -> 블레이드 처짐 감지 , Calibration, setting, check
|
Macro -> 무한동작 매크로 (접근 막혀있음)
|
====================================
|
|
======== Teaching ======================
|
이거는 팬던트에서만 하는게 맞을듯.
|
====================================
|
|
======= Speed (%) ==============
|
ex ) System 속도 50% , Jog 속도 50% -> 실제 Jog 속도 25%.
|
|
System -> 전체의 동작 속도
|
Jog -> System 대비 jog 속도
|
Home -> System 대비 Home 속도
|
Wafer On -> System 대비 팔을 뻗고 접는 동작
|
Wafer Off -> System 대비 팔을 뻗고 접는 동작
|
Z Up -> System 대비 Z축 Up 수행시
|
Z Down -> System 대비 Z축 Down 수행시
|
================================
|
|
======== Monitor ======================
|
IO Control -> IO on/off제어, Grip on/off speed 확인
|
Input monitor -> 로봇 수신 input 확인.
|
output monitor -> 로봇 수신 output 확인
|
Limit sensor -> Limit sensor 감지 확인
|
ERRLog -> 과거 발생했던 에러 확인
|
Serial Port -> 로봇 통신 설정 변경
|
====================================
|
|
======== Setup ======================
|
Zero degree set -> 모든 축의 원점 위치 현재 로봇의 위치로 설정. // 팬던트에서만
|
Calibration -> Z축 탈조 자동 감지 확인 칼리브레이션 수행. // 기능이 있는지 오면 확인.
|
Soft limit -> 각축의 이동 가능 범위 재설정. // 팬던트 에서만.
|
Motor speed -> 각 축의 Motor 최대 동작 속도 변경 100%(3000RPM) // 팬던트 에서만.
|
Mode ->
|
Demo mode,
|
Interlock mode (외부 Interlock 신호시 로봇 정지 유무),
|
retry cnt (Get, Put 동작 실패 시 재시도 횟수) 설정
|
Wafer size 설정,
|
Non block (1 command 내의 구분동작 연결 속도빠르게) //안씀.
|
|
Time -> 그립형/버큠형 타입의 경우 On/Off 완료 대기 딜레이 시간 조절.(ms)
|
====================================
|
|
======== Jog ======================
|
이거는 팬던트에서만 하는게 맞을듯.
|
====================================
|
|
알람 너무 많은데...
|
Alarm 은 하나로 해놓고 Error 내용이랑 Description만 띄우면 되지 않을까?
|
*/
|
public class Robot : ComPort
|
{
|
public enum PowerState
|
{
|
/// <summary>
|
/// System initially starting up
|
/// </summary>
|
Starting,
|
/// <summary>
|
/// Power off, fatal error has occurred
|
/// </summary>
|
FatalError,
|
/// <summary>
|
/// Power off, power sequence restarting
|
/// </summary>
|
PowerSequencereStarting,
|
/// <summary>
|
/// Power being turned off, no fault condition has occurred
|
/// </summary>
|
PowerBeingTrunedOff,
|
/// <summary>
|
/// Power being turned off, a fault condition has occurred
|
/// </summary>
|
PowerBeingTurnedOffFault,
|
/// <summary>
|
/// Power is off, a fault has occurred that must be cleared
|
/// </summary>
|
PowerOffFault,
|
/// <summary>
|
/// Power is off, waiting for hardware enable power switch to be turned off
|
/// </summary>
|
PowerOffWaitingHardware,
|
/// <summary>
|
/// Power is off, waiting for enable power signal to be asserted
|
/// </summary>
|
PowerOffWaitingPowerSignal,
|
/// <summary>
|
/// Power is coming up, enabling amplifiers
|
/// </summary>
|
PowerComingUp,
|
/// <summary>
|
/// Power is on, performing motor commutation
|
/// </summary>
|
PowerOnPerformingMotor,
|
/// <summary>
|
/// Power is coming up, enabling servos and releasing brakes
|
/// </summary>
|
PowerComingUpEnablingServos,
|
/// <summary>
|
/// Power is on, waiting to execute thread or Auto Execution task
|
/// </summary>
|
PowerOnWaitingExecuteThread,
|
/// <summary>
|
/// Power is on, executing Auto Execution tas
|
/// </summary>
|
PowerOnExecutingAuto,
|
}
|
|
public enum StageList : int
|
{
|
Port1 = 1,
|
Port2,
|
AlignFlip,
|
Align,
|
Chamber,
|
}
|
|
private string _fimwareVersion;
|
|
private bool _isError;
|
private bool _isMappingError;
|
|
// 0 ~ 10 서보 off 상태 11 ~ 12 서보 on 상태
|
private PowerState _powerStatus;
|
|
private Equipment _equipment;
|
private Thread t_statusUpdate;
|
|
private double _positionT;
|
private double _positionZ;
|
private double _positionR;
|
private double _positionF;
|
private string _alarmCode;
|
private string _alarmDescription;
|
private bool _isWaferExist;
|
private bool _isVacuumOn;
|
private bool _isRun;
|
private bool _isPutGetRun;
|
|
private TimeSpan _getTactTime;
|
private TimeSpan _putTactTime;
|
private TimeSpan _mappingTactTime;
|
|
private Thread t_PutGetSequence;
|
|
public double PositionT
|
{
|
get
|
{
|
return _positionT;
|
}
|
|
set
|
{
|
_positionT = value;
|
}
|
}
|
|
public double PositionZ
|
{
|
get
|
{
|
return _positionZ;
|
}
|
|
set
|
{
|
_positionZ = value;
|
}
|
}
|
|
public double PositionR
|
{
|
get
|
{
|
return _positionR;
|
}
|
|
set
|
{
|
_positionR = value;
|
}
|
}
|
|
public double PositionF
|
{
|
get
|
{
|
return _positionF;
|
}
|
|
set
|
{
|
_positionF = value;
|
}
|
}
|
|
public string AlarmCode
|
{
|
get
|
{
|
return _alarmCode;
|
}
|
|
set
|
{
|
_alarmCode = value;
|
}
|
}
|
|
public string AlarmDescription
|
{
|
get
|
{
|
return _alarmDescription;
|
}
|
|
set
|
{
|
_alarmDescription = value;
|
}
|
}
|
|
public bool IsError
|
{
|
get
|
{
|
return _isError;
|
}
|
|
set
|
{
|
_isError = value;
|
}
|
}
|
|
public PowerState PowerStatus
|
{
|
get
|
{
|
return _powerStatus;
|
}
|
|
private set
|
{
|
_powerStatus = value;
|
}
|
}
|
|
public bool IsVacuumOn
|
{
|
get
|
{
|
return _isVacuumOn;
|
}
|
|
private set
|
{
|
_isVacuumOn = value;
|
}
|
}
|
|
public bool IsRun
|
{
|
get
|
{
|
return _isRun;
|
}
|
|
set
|
{
|
_isRun = value;
|
}
|
}
|
|
public bool IsWaferExist
|
{
|
get
|
{
|
return _isWaferExist;
|
}
|
|
set
|
{
|
_isWaferExist = value;
|
}
|
}
|
|
public bool IsServoOn
|
{
|
get
|
{
|
if(_powerStatus == PowerState.PowerOnWaitingExecuteThread || _powerStatus == PowerState.PowerOnExecutingAuto)
|
{
|
return true;
|
}
|
else
|
{
|
return false;
|
}
|
}
|
}
|
|
public bool IsPutGetRun
|
{
|
get
|
{
|
return _isPutGetRun;
|
}
|
|
set
|
{
|
_isPutGetRun = value;
|
}
|
}
|
|
public TimeSpan GetTactTime
|
{
|
get
|
{
|
return _getTactTime;
|
}
|
|
set
|
{
|
_getTactTime = value;
|
}
|
}
|
|
public TimeSpan PutTactTime
|
{
|
get
|
{
|
return _putTactTime;
|
}
|
|
set
|
{
|
_putTactTime = value;
|
}
|
}
|
|
public bool IsRunEnable
|
{
|
get
|
{
|
if (IsOpen && IsRun == false && (t_PutGetSequence == null || (t_PutGetSequence.ThreadState == ThreadState.Stopped)))
|
{
|
return true;
|
}
|
else
|
{
|
return false;
|
}
|
}
|
}
|
|
public TimeSpan MappingTactTime
|
{
|
get
|
{
|
return _mappingTactTime;
|
}
|
|
set
|
{
|
_mappingTactTime = value;
|
}
|
}
|
|
public bool IsMappingError
|
{
|
get
|
{
|
return _isMappingError;
|
}
|
|
set
|
{
|
_isMappingError = value;
|
}
|
}
|
|
public Robot(Equipment equipment)
|
{
|
serialPort.PortName = "COM9";
|
serialPort.BaudRate = 57600;
|
serialPort.Parity = System.IO.Ports.Parity.None;
|
serialPort.DataBits = 8;
|
serialPort.StopBits = System.IO.Ports.StopBits.One;
|
serialPort.ReadTimeout = 5000;
|
ReceiveWaitSeconds = 0.05;
|
Terminator = "\r\n";
|
|
_equipment = equipment;
|
|
t_statusUpdate = new Thread(statusUpdate);
|
t_statusUpdate.Start();
|
_alarmCode = "0";
|
}
|
|
public void statusUpdate()
|
{
|
while (_equipment.IsDisposed == false)
|
{
|
try
|
{
|
Thread.Sleep(10);
|
|
if (IsOpen)
|
{
|
ReadPowerState();
|
ReadPosition();
|
ReadErrorCode();
|
ReadWaferDetected();
|
ReadVacuumOn();
|
ReadRun();
|
|
}
|
else
|
{
|
if (_equipment.alarmManager.OccurredAlarms.Exists(x => x.Code == SA_LTT.AlarmCode.AL_0052_ROBOT_DISCONNECTED))
|
{
|
|
}
|
else
|
{
|
WaferGetInterlock(StageList.Chamber, 1);
|
if (Open() == false)
|
{
|
_equipment.alarmManager.Occur(SA_LTT.AlarmCode.AL_0052_ROBOT_DISCONNECTED);
|
}
|
else
|
{
|
Thread.Sleep(100);
|
ReadFirmwareVersion();
|
}
|
}
|
}
|
}
|
catch (Exception e)
|
{
|
EquipmentLogManager.Instance.WriteExceptionLog(e.StackTrace);
|
}
|
}
|
}
|
|
|
public void ReadFirmwareVersion()
|
{
|
if(IsOpen)
|
{
|
string receivedData;
|
WriteRead("VER", out receivedData);
|
_fimwareVersion = receivedData;
|
}
|
else
|
{
|
// 읽기 실패 알람 ?
|
}
|
}
|
|
//=================== Movement ======================
|
public bool GetReady(StageList stage, int slot = 1)
|
{
|
if (t_PutGetSequence == null || t_PutGetSequence.ThreadState == ThreadState.Stopped)
|
{
|
t_PutGetSequence = new Thread(() => GetReadyThread(stage, slot));
|
t_PutGetSequence.Start();
|
return true;
|
}
|
else
|
{
|
return false;
|
}
|
}
|
|
public void GetReadyThread(StageList stage, int slot = 1)
|
{
|
try
|
{
|
DateTime tactTime = DateTime.Now;
|
IsPutGetRun = true;
|
|
Write($"GRDY {(int)stage},{slot}");
|
|
DateTime dt = DateTime.Now;
|
|
//동작 진행 확인.
|
while (true)
|
{
|
if (IsRun)
|
{
|
break;
|
}
|
else
|
{
|
if ((DateTime.Now - dt).TotalSeconds > 5)
|
{
|
PutTactTime = DateTime.Now - tactTime;
|
return;
|
}
|
}
|
}
|
|
//동작 진행 완료 확인
|
while (true)
|
{
|
if (IsRun == false)
|
{
|
break;
|
}
|
else
|
{
|
if ((DateTime.Now - dt).TotalMinutes > 3)
|
{
|
return;
|
}
|
}
|
}
|
}
|
catch (Exception e)
|
{
|
EquipmentLogManager.Instance.WriteExceptionLog(e.StackTrace);
|
}
|
finally
|
{
|
IsPutGetRun = false;
|
}
|
}
|
|
public bool Get(StageList stage, int slot = 1)
|
{
|
if (WaferGetInterlock(stage, slot) == false)
|
{
|
if (t_PutGetSequence == null || t_PutGetSequence.ThreadState == ThreadState.Stopped)
|
{
|
t_PutGetSequence = new Thread(() => GetThread(stage, slot));
|
t_PutGetSequence.Start();
|
|
return true;
|
}
|
else
|
{
|
return false;
|
}
|
}
|
else
|
{
|
return false;
|
}
|
}
|
|
private void GetThread(StageList stage, int slot)
|
{
|
try
|
{
|
DateTime tactTime = DateTime.Now;
|
IsPutGetRun = true;
|
|
Write($"GET {(int)stage},{slot}");
|
|
DateTime dt = DateTime.Now;
|
|
//동작 진행 확인.
|
while (true)
|
{
|
if (IsRun)
|
{
|
break;
|
}
|
else
|
{
|
if ((DateTime.Now - dt).TotalSeconds > 5)
|
{
|
GetTactTime = DateTime.Now - tactTime;
|
return;
|
}
|
}
|
}
|
|
//동작 진행 완료 확인
|
while (true)
|
{
|
if (IsRun == false)
|
{
|
WaferNumbers sourceNumber;
|
|
WaferInfoManager.TryParse((int)stage, slot, out sourceNumber);
|
|
Thread.Sleep(100);
|
ReadWaferDetected();
|
|
if (IsWaferExist == true)
|
{
|
if (stage == StageList.AlignFlip)
|
{
|
WaferInfo waferInfo = _equipment.waferInfoManager.GetWaferInfo(sourceNumber);
|
waferInfo.IsFlip = !waferInfo.IsFlip;
|
_equipment.waferInfoManager.SetWaferInfo(sourceNumber, waferInfo);
|
}
|
|
_equipment.waferInfoManager.MoveWaferInfo(sourceNumber, WaferNumbers.Robot);
|
}
|
else
|
{
|
EquipmentLogManager.Instance.WriteExceptionLog("Get Error");
|
}
|
|
GetTactTime = DateTime.Now - tactTime;
|
break;
|
}
|
else
|
{
|
if ((DateTime.Now - dt).TotalMinutes > 3)
|
{
|
//Robot 동작완료 TimeOut 3분
|
GetTactTime = DateTime.Now - tactTime;
|
return;
|
}
|
}
|
}
|
}
|
catch (Exception e)
|
{
|
EquipmentLogManager.Instance.WriteExceptionLog(e.StackTrace);
|
}
|
finally
|
{
|
IsPutGetRun = false;
|
}
|
}
|
|
public bool PutReady(StageList stage, int slot = 1)
|
{
|
if (t_PutGetSequence == null || t_PutGetSequence.ThreadState == ThreadState.Stopped)
|
{
|
t_PutGetSequence = new Thread(() => PutReadyThread(stage, slot));
|
t_PutGetSequence.Start();
|
return true;
|
}
|
else
|
{
|
return false;
|
}
|
}
|
|
public void PutReadyThread(StageList stage, int slot = 1)
|
{
|
try
|
{
|
DateTime tactTime = DateTime.Now;
|
IsPutGetRun = true;
|
|
Write($"PRDY {(int)stage},{slot}");
|
|
DateTime dt = DateTime.Now;
|
|
//동작 진행 확인.
|
while (true)
|
{
|
if (IsRun)
|
{
|
break;
|
}
|
else
|
{
|
if ((DateTime.Now - dt).TotalSeconds > 5)
|
{
|
PutTactTime = DateTime.Now - tactTime;
|
return;
|
}
|
}
|
}
|
|
//동작 진행 완료 확인
|
while (true)
|
{
|
if (IsRun == false)
|
{
|
break;
|
}
|
else
|
{
|
if ((DateTime.Now - dt).TotalMinutes > 3)
|
{
|
return;
|
}
|
}
|
}
|
}
|
catch (Exception e)
|
{
|
EquipmentLogManager.Instance.WriteExceptionLog(e.StackTrace);
|
}
|
finally
|
{
|
IsPutGetRun = false;
|
}
|
}
|
|
public bool Put(StageList stage, int slot = 1)
|
{
|
if (WaferPutInterlock(stage, slot) == false)
|
{
|
if (t_PutGetSequence == null || t_PutGetSequence.ThreadState == ThreadState.Stopped)
|
{
|
t_PutGetSequence = new Thread(() => PutThread(stage, slot));
|
t_PutGetSequence.Start();
|
|
return true;
|
}
|
else
|
{
|
return false;
|
}
|
}
|
else
|
{
|
return false;
|
}
|
}
|
|
private void PutThread(StageList stage, int slot)
|
{
|
try
|
{
|
DateTime tactTime = DateTime.Now;
|
IsPutGetRun = true;
|
|
Write($"PUT {(int)stage},{slot}");
|
|
DateTime dt = DateTime.Now;
|
|
//동작 진행 확인.
|
while (true)
|
{
|
if (IsRun)
|
{
|
break;
|
}
|
else
|
{
|
if ((DateTime.Now - dt).TotalSeconds > 5)
|
{
|
PutTactTime = DateTime.Now - tactTime;
|
return;
|
}
|
}
|
}
|
|
//동작 진행 완료 확인
|
while (true)
|
{
|
if (IsRun == false)
|
{
|
WaferNumbers destinationNumber;
|
|
WaferInfoManager.TryParse((int)stage, slot, out destinationNumber);
|
|
Thread.Sleep(100);
|
|
ReadWaferDetected();
|
|
if (IsWaferExist == false)
|
{
|
if (stage == StageList.AlignFlip)
|
{
|
WaferInfo waferInfo = _equipment.waferInfoManager.GetWaferInfo(WaferNumbers.Robot);
|
waferInfo.IsFlip = !waferInfo.IsFlip;
|
_equipment.waferInfoManager.SetWaferInfo(WaferNumbers.Robot, waferInfo);
|
}
|
|
_equipment.waferInfoManager.MoveWaferInfo(WaferNumbers.Robot, destinationNumber);
|
}
|
else
|
{
|
EquipmentLogManager.Instance.WriteExceptionLog("Put Error");
|
}
|
|
PutTactTime = DateTime.Now - tactTime;
|
break;
|
}
|
else
|
{
|
if ((DateTime.Now - dt).TotalMinutes > 3)
|
{
|
//Robot 동작완료 TimeOut 3분
|
PutTactTime = DateTime.Now - tactTime;
|
return;
|
}
|
}
|
}
|
}
|
catch (Exception e)
|
{
|
EquipmentLogManager.Instance.WriteExceptionLog(e.StackTrace);
|
}
|
finally
|
{
|
IsPutGetRun = false;
|
}
|
}
|
|
public bool MappingSeq(int stage)
|
{
|
if (MappingInterlock(stage) == false)
|
{
|
if (t_PutGetSequence == null || t_PutGetSequence.ThreadState == ThreadState.Stopped)
|
{
|
t_PutGetSequence = new Thread(() => MappingTh(stage));
|
t_PutGetSequence.Start();
|
|
return true;
|
}
|
else
|
{
|
return false;
|
}
|
}
|
else
|
{
|
return false;
|
}
|
}
|
|
public bool WaferGetInterlock(StageList stage, int slot)
|
{
|
if(IsWaferExist || IsRunEnable == false || IsPutGetRun)
|
{
|
if(IsWaferExist)
|
{
|
_equipment.alarmManager.Occur(SA_LTT.AlarmCode.AL_0077_ROBOT_HAS_WAFER);
|
}
|
|
return true;
|
}
|
else
|
{
|
WaferNumbers waferNumber = WaferNumbers.A1;
|
|
if(WaferInfoManager.TryParse((int)stage, slot, out waferNumber))
|
{
|
if (stage == StageList.Port1)
|
{
|
if(_equipment.crevis.DigitalInputs[Crevis.DigitalInput.CST_DETECTOR_1] == false)
|
{
|
_equipment.alarmManager.Occur(SA_LTT.AlarmCode.AL_0070_PORT1_IS_NOT_DETECTED);
|
return true;
|
}
|
}
|
|
if (stage == StageList.Port2)
|
{
|
if (_equipment.crevis.DigitalInputs[Crevis.DigitalInput.CST_DETECTOR_2] == false)
|
{
|
_equipment.alarmManager.Occur(SA_LTT.AlarmCode.AL_0071_PORT2_IS_NOT_DETECTED);
|
return true;
|
}
|
}
|
|
if (stage == StageList.AlignFlip || stage == StageList.Align)
|
{
|
if (_equipment.preAligner.IsWaferExist == false)
|
{
|
_equipment.alarmManager.Occur(SA_LTT.AlarmCode.AL_0072_PREALIGNER_HAS_NOT_WAFER);
|
return true;
|
}
|
|
if(_equipment.preAligner.IsRunEnable == false)
|
{
|
return true;
|
}
|
}
|
|
if (stage == StageList.Chamber)
|
{
|
//Position, Gate, LiftPin Check
|
if (_equipment.powerPmac.IsLoadPosition() == false || _equipment.crevis.DigitalInputs[Crevis.DigitalInput.CMB_GATE_CLOSE] || _equipment.crevis.DigitalInputs[Crevis.DigitalInput.WAFER_DOWN_CYLINDER])
|
{
|
_equipment.SetMessageBox("Chamber position을 확인 해 주세요.");
|
//_equipment.alarmManager.Occur(SA_LTT.AlarmCode.AL_0073_CHAMBER_HAS_NOT_WAFER);
|
return true;
|
}
|
}
|
|
if (_equipment.waferInfoManager.GetWaferInfo(waferNumber).IsStatus == WaferInfo.WaferStatus.Exist)
|
{
|
return false;
|
}
|
else
|
{
|
_equipment.SetMessageBox("이미 Wafer가 존재 하지 않습니다! Wafer 정보를 확인해 주세요.");
|
return true;
|
}
|
}
|
else
|
{
|
return true;
|
}
|
}
|
}
|
|
public bool WaferPutInterlock(StageList stage, int slot)
|
{
|
if(IsWaferExist == false|| IsRunEnable == false || IsPutGetRun)
|
{
|
if (IsWaferExist == false)
|
{
|
_equipment.alarmManager.Occur(SA_LTT.AlarmCode.AL_0074_ROBOT_HAS_NOT_WAFER);
|
}
|
|
return true;
|
}
|
else
|
{
|
WaferNumbers waferNumber = WaferNumbers.A1;
|
if (WaferInfoManager.TryParse((int)stage, slot, out waferNumber))
|
{
|
if (stage == StageList.Port1)
|
{
|
if (_equipment.crevis.DigitalInputs[Crevis.DigitalInput.CST_DETECTOR_1] == false)
|
{
|
_equipment.alarmManager.Occur(SA_LTT.AlarmCode.AL_0070_PORT1_IS_NOT_DETECTED);
|
return true;
|
}
|
}
|
|
if (stage == StageList.Port2)
|
{
|
if (_equipment.crevis.DigitalInputs[Crevis.DigitalInput.CST_DETECTOR_2] == false)
|
{
|
_equipment.alarmManager.Occur(SA_LTT.AlarmCode.AL_0071_PORT2_IS_NOT_DETECTED);
|
return true;
|
}
|
}
|
|
if (stage == StageList.AlignFlip || stage == StageList.Align)
|
{
|
if (_equipment.preAligner.IsWaferExist)
|
{
|
_equipment.alarmManager.Occur(SA_LTT.AlarmCode.AL_0075_PREALIGNER_HAS_WAFER);
|
return true;
|
}
|
}
|
|
if (stage == StageList.Chamber)
|
{
|
//Position, Gate, LiftPin Check
|
if (_equipment.powerPmac.IsLoadPosition() == false || _equipment.crevis.DigitalInputs[Crevis.DigitalInput.CMB_GATE_CLOSE] || _equipment.crevis.DigitalInputs[Crevis.DigitalInput.WAFER_DOWN_CYLINDER])
|
{
|
_equipment.SetMessageBox("Chamber position을 확인 해 주세요.");
|
//_equipment.alarmManager.Occur(SA_LTT.AlarmCode.AL_0076_CHAMBER_HAS_WAFER);
|
|
return true;
|
}
|
}
|
|
if (_equipment.waferInfoManager.GetWaferInfo(waferNumber).IsStatus == WaferInfo.WaferStatus.Empty)
|
{
|
return false;
|
}
|
else
|
{
|
_equipment.SetMessageBox("이미 Wafer가 존재 합니다! Wafer 정보를 확인해 주세요.");
|
return true;
|
}
|
}
|
else
|
{
|
return true;
|
}
|
}
|
}
|
|
public bool MappingInterlock(int stage)
|
{
|
if (stage == 1)
|
{
|
if(_equipment.crevis.DigitalInputs[Crevis.DigitalInput.CST_DETECTOR_1])
|
{
|
return false;
|
}
|
else
|
{
|
_equipment.alarmManager.Occur(SA_LTT.AlarmCode.AL_0070_PORT1_IS_NOT_DETECTED);
|
return true;
|
}
|
}
|
else if (stage == 2)
|
{
|
if (_equipment.crevis.DigitalInputs[Crevis.DigitalInput.CST_DETECTOR_2])
|
{
|
return false;
|
}
|
else
|
{
|
_equipment.alarmManager.Occur(SA_LTT.AlarmCode.AL_0071_PORT2_IS_NOT_DETECTED);
|
return true;
|
}
|
}
|
else
|
{
|
return true;
|
}
|
}
|
|
private void MappingTh(int stage)
|
{
|
DateTime tactTime = DateTime.Now;
|
Mapping(stage);
|
|
DateTime dt = DateTime.Now;
|
|
//동작 진행 확인.
|
while (true)
|
{
|
if (IsRun)
|
{
|
break;
|
}
|
else
|
{
|
if ((DateTime.Now - dt).TotalSeconds > 5)
|
{
|
PutTactTime = DateTime.Now - tactTime;
|
return;
|
}
|
}
|
}
|
|
while (true)
|
{
|
//Run 종료 후 Mapping 결과 받기 시작.
|
if (IsRun == false)
|
{
|
if (stage == 1)
|
{
|
ReadPort1MappingResult();
|
}
|
else if (stage == 2)
|
{
|
ReadPort2MappingResult();
|
}
|
|
MappingTactTime = DateTime.Now - tactTime;
|
break;
|
}
|
else
|
{
|
if ((DateTime.Now - dt).TotalMinutes > 5)
|
{
|
//Robot 동작완료 TimeOut 5분
|
MappingTactTime = DateTime.Now - tactTime;
|
return;
|
}
|
}
|
}
|
}
|
|
private void ReadPort1MappingResult()
|
{
|
string mappingData = _equipment.robot.ReadMappingResult();
|
|
if (mappingData.Length == 25)
|
{
|
IsMappingError = false;
|
for (int i = 0; i < 25; i++)
|
{
|
WaferInfo info = _equipment.waferInfoManager.GetWaferInfo(WaferInfoManager.WaferNumbers.A1 + i);
|
info.SourceNumber = WaferInfoManager.WaferNumbers.A1 + i;
|
info.IsProcessComplete = false;
|
|
if (mappingData[i] == '0')
|
{
|
info.IsStatus = WaferInfo.WaferStatus.Empty;
|
}
|
else if (mappingData[i] == '1')
|
{
|
info.IsStatus = WaferInfo.WaferStatus.Exist;
|
}
|
else if (mappingData[i] == 'C')
|
{
|
info.IsStatus = WaferInfo.WaferStatus.Leaning;
|
}
|
else if (mappingData[i] == 'D')
|
{
|
info.IsStatus = WaferInfo.WaferStatus.Overlap;
|
}
|
|
info.RecipeName = _equipment.port1Foup.foupRecipe.RecipeNames[i];
|
_equipment.waferInfoManager.SetWaferInfo(WaferInfoManager.WaferNumbers.A1 + i, info);
|
}
|
}
|
else
|
{
|
IsMappingError = true;
|
for (int i = 0; i < 25; i++)
|
{
|
WaferInfo info = _equipment.waferInfoManager.GetWaferInfo(WaferInfoManager.WaferNumbers.A1 + i);
|
info.IsStatus = WaferInfo.WaferStatus.Empty;
|
info.SourceNumber = WaferInfoManager.WaferNumbers.A1 + i;
|
_equipment.waferInfoManager.SetWaferInfo(WaferInfoManager.WaferNumbers.A1 + i, info);
|
}
|
}
|
}
|
|
private void ReadPort2MappingResult()
|
{
|
string mappingData = _equipment.robot.ReadMappingResult();
|
|
if (mappingData.Length == 25)
|
{
|
IsMappingError = false;
|
for (int i = 0; i < 25; i++)
|
{
|
WaferInfo info = _equipment.waferInfoManager.GetWaferInfo(WaferInfoManager.WaferNumbers.B1 + i);
|
info.SourceNumber = WaferInfoManager.WaferNumbers.B1 + i;
|
info.IsProcessComplete = false;
|
|
if (mappingData[i] == '0')
|
{
|
info.IsStatus = WaferInfo.WaferStatus.Empty;
|
}
|
else if (mappingData[i] == '1')
|
{
|
info.IsStatus = WaferInfo.WaferStatus.Exist;
|
}
|
else if (mappingData[i] == 'C')
|
{
|
info.IsStatus = WaferInfo.WaferStatus.Leaning;
|
}
|
else if (mappingData[i] == 'D')
|
{
|
info.IsStatus = WaferInfo.WaferStatus.Overlap;
|
}
|
|
info.RecipeName = _equipment.port2Foup.foupRecipe.RecipeNames[i];
|
_equipment.waferInfoManager.SetWaferInfo(WaferInfoManager.WaferNumbers.B1 + i, info);
|
}
|
}
|
else
|
{
|
IsMappingError = true;
|
for (int i = 0; i < 25; i++)
|
{
|
WaferInfo info = _equipment.waferInfoManager.GetWaferInfo(WaferInfoManager.WaferNumbers.B1 + i);
|
info.IsStatus = WaferInfo.WaferStatus.Empty;
|
info.SourceNumber = WaferInfoManager.WaferNumbers.B1 + i;
|
_equipment.waferInfoManager.SetWaferInfo(WaferInfoManager.WaferNumbers.A1 + i, info);
|
}
|
}
|
}
|
|
public void Mapping(int stage)
|
{
|
Write($"MAP {stage}");
|
}
|
|
public string ReadMappingResult()
|
{
|
string receivedData;
|
WriteRead("MLD", out receivedData);
|
//0 없음 1 있음 C 기울어짐 D 겹침
|
//000000000000000000000000000000000000000000
|
|
return receivedData;
|
}
|
|
public void Home()
|
{
|
Write("ORG");
|
}
|
|
public void ServoOn()
|
{
|
Write("ENABLE");
|
}
|
|
public void ServoOff()
|
{
|
Write("DISABLE");
|
}
|
|
public void MoveRelative(double x, double y, double z)
|
{
|
Write($"LMI {x},{y},{z}");
|
}
|
|
public void MoveAbsolute(double x, double y, double z)
|
{
|
Write($"LMA {x},{y},{z}");
|
}
|
|
//====================================================
|
|
//=================== Speed ======================
|
public void ReadMappingSpeed()
|
{
|
string receivedData;
|
WriteRead("RMPS", out receivedData);
|
//RMPS V01=030
|
}
|
|
public void SetMappingSpeed(int speed)
|
{
|
Write($"WMPS {speed}");
|
}
|
|
/// <summary>
|
///
|
/// </summary>
|
/// <param name="thickness">1 -> 0.001mm</param>
|
public void SetWaferThickness(int thickness)
|
{
|
Write($"WWTH {thickness}"); //100 -> 1mm
|
}
|
|
public void SetWaferCrossCheckStandard(int standard)
|
{
|
Write($"WSCT {standard}"); // %
|
}
|
|
public void SetWaferDoubleCheckStandard(int standard)
|
{
|
Write($"WSDT {standard}"); // %
|
}
|
//====================================================
|
|
//=================== Monitor =======================
|
public void ReadErrorCode()
|
{
|
string receivedData;
|
|
if (WriteRead("ERR", out receivedData))
|
{
|
AlarmCode = receivedData;
|
|
if (receivedData != "0")
|
{
|
_equipment.alarmManager.Occur(SA_LTT.AlarmCode.AL_0200_ROBOT_ALARM_OCCURED);
|
EquipmentLogManager.Instance.WriteProcessLog($"Robot alarm code : {receivedData}");
|
IsError = true;
|
ReadErrorDescription();
|
}
|
else
|
{
|
AlarmDescription = string.Empty;
|
IsError = false;
|
}
|
}
|
//ERR 201
|
}
|
|
public void ReadErrorDescription()
|
{
|
string receivedData;
|
WriteRead("ERD", out receivedData);
|
AlarmDescription = receivedData;
|
//ERD -1027*JOINT-OUT-OF-RANGE* 1:2 ORG
|
}
|
|
public void ErrorClear()
|
{
|
Write("DRT");
|
}
|
|
public void ReadPowerState()
|
{
|
string receivedData;
|
WriteRead("RPS", out receivedData);
|
|
string[] splitData = receivedData.Split('=');
|
|
PowerState powerState;
|
|
if(splitData.Length == 2 && Enum.TryParse(splitData[1], out powerState))
|
{
|
PowerStatus = powerState;
|
}
|
}
|
|
public void ReadPosition()
|
{
|
string receivedData;
|
WriteRead("NMPS", out receivedData);
|
string[] splitData = receivedData.Split(',');
|
// +0116.791,+0025.006,-0028.258,+0000.000
|
if (splitData.Length == 4)
|
{
|
PositionT = double.Parse(splitData[0]);
|
PositionZ = double.Parse(splitData[1]);
|
PositionR = double.Parse(splitData[2]);
|
PositionF = double.Parse(splitData[3]);
|
}
|
else
|
{
|
|
}
|
}
|
|
public void EMS()
|
{
|
Write("AES");
|
}
|
|
public void ReadSystemSpeed()
|
{
|
string receivedData;
|
WriteRead("RSSP", out receivedData);
|
//RSPD V01 = 100
|
}
|
//====================================================
|
|
//=================== Setup =======================
|
public void SetSystemSpeed(int speed)
|
{
|
Write($"WSSP {speed}");
|
}
|
|
public void ReadJogSpeed()
|
{
|
string receivedData;
|
WriteRead("RJSS", out receivedData);
|
//RJSS V01=030,V02=30
|
}
|
|
public void ReadWaferDetected()
|
{
|
string receivedData;
|
WriteRead("RIDI 1", out receivedData);
|
int dec = 0;
|
|
if (receivedData != string.Empty)
|
{
|
try
|
{
|
dec = Convert.ToInt32(receivedData, 16);
|
|
BitArray bitarray = new BitArray(new byte[] { Convert.ToByte(dec) });
|
|
IsWaferExist = bitarray[0];
|
}
|
catch(Exception e)
|
{
|
|
}
|
}
|
else
|
{
|
|
}
|
}
|
|
public void ReadVacuumOn()
|
{
|
string receivedData;
|
WriteRead("RIDI 5", out receivedData);
|
|
int dec = 0;
|
|
if (receivedData != string.Empty)
|
{
|
try
|
{
|
dec = Convert.ToInt32(receivedData, 16);
|
|
BitArray bitarray = new BitArray(new byte[] { Convert.ToByte(dec) });
|
|
IsVacuumOn = !bitarray[0];
|
}
|
catch (Exception e)
|
{
|
|
}
|
}
|
else
|
{
|
|
}
|
}
|
|
public void ReadRun()
|
{
|
string receivedData;
|
WriteRead("NIDO 1", out receivedData);
|
|
int dec = 0;
|
|
if (receivedData != string.Empty)
|
{
|
try
|
{
|
dec = Convert.ToInt32(receivedData, 16);
|
|
BitArray bitarray = new BitArray(new byte[] { Convert.ToByte(dec) });
|
|
IsRun = bitarray[4];
|
}
|
catch (Exception e)
|
{
|
|
}
|
}
|
else
|
{
|
|
}
|
}
|
|
public void SetJogSpeed(int speed)
|
{
|
Write($"WJSS {speed}");
|
}
|
|
public void ReadHomeSpeed()
|
{
|
string receivedData;
|
WriteRead("RHMS", out receivedData);
|
//RHMS V01=020,V02=20
|
}
|
|
public void SetHomeSpeed(int speed)
|
{
|
Write($"WHMS {speed}");
|
}
|
|
public void ReadWaferOnSpeed()
|
{
|
string receivedData;
|
WriteRead("RHIS", out receivedData);
|
//RHIS V01=060,V02=060
|
}
|
|
public void SetWaferOnSpeed(int speed)
|
{
|
Write($"WHIS {speed}");
|
}
|
|
public void ReadWaferOffSpeed()
|
{
|
string receivedData;
|
WriteRead("RLOS", out receivedData);
|
//RLOS V01=020,V02=020
|
}
|
|
public void SetWaferOffSpeed(int speed)
|
{
|
Write($"WLOS {speed}");
|
}
|
|
public void ReadZSpeed()
|
{
|
string receivedData;
|
WriteRead("RZSP", out receivedData);
|
//RZSP V01=015,V02=015
|
//UP 속도 , DOWN 속도
|
}
|
|
public void SetZSpeed(int upSpeed, int downSpeed)
|
{
|
Write($"WZSP {upSpeed},{downSpeed}");
|
}
|
|
public void EmergencyStop()
|
{
|
Write("AES");
|
}
|
|
public void Pause()
|
{
|
Write("PAUSE 1");
|
}
|
|
public void Run()
|
{
|
Write("PAUSE 0");
|
}
|
|
/// <summary>
|
/// 지정된 채널 번호 부터 m개의 채널 값을 2자리수의 16진로 받습니다.
|
/// 1개의 채널은 8개의 I/O bit 를 포함합니다.
|
/// PRC Input I/O Map 은 I/O 번호가 10001 번부터 시작합니다.
|
/// </summary>
|
public void ReadInput()
|
{
|
string receivedData;
|
WriteRead("NIDI", out receivedData);
|
}
|
|
/// <summary>
|
/// 지정된 채널 번호 부터 m개의 채널 값을 2자리수의 16진로 받습니다.
|
/// 1개의 채널은 8개의 I/O bit 를 포함합니다.
|
/// PRC Output I/O Map 은 I/O 번호가 13 번부터 시작합니다
|
/// </summary>
|
public void ReadOutput()
|
{
|
string receivedData;
|
WriteRead("NIDO", out receivedData);
|
}
|
//====================================================
|
|
public new bool Write(string command)
|
{
|
base.Write(command + $"\r\n");
|
|
return true;
|
}
|
|
public bool WriteRead(string command, out string receivedData)
|
{
|
string data = base.WriteRead(command + $"\r\n");
|
if (data.StartsWith(command.Split(' ')[0]))
|
{
|
receivedData = data.Remove(0, command.Split(' ')[0].Length + 1).Replace($"\r\n", "");
|
return true;
|
}
|
else
|
{
|
receivedData = string.Empty;
|
return false;
|
}
|
}
|
}
|
|
enum RobotAlarm
|
{
|
ERR_NOT_HOMED = 2,
|
ERR_EMERGENCY = 4,
|
ERR_MOTOR_ERROR = 12,
|
ERR_WAIT_TIMEOUT = 190,
|
ENCODER_RESET_TIMEOUT = 193,
|
ERR_INTERLOCK = 194,
|
ERR_DATA_RANGE = 201,
|
ERR_WAFER_BEFORE_GET = 202,
|
ERR_NO_WAFER_BEFORE_PUT = 203,
|
ERR_NO_WAFER_AFTER_GET = 204,
|
ERR_WAFER_AFTER_PUT = 205,
|
ERR_NO_WAFER_DURING_GET = 206,
|
ERR_WAFER_DURING_PUT = 207,
|
ERR_NOT_HOMED_1 = 208,
|
ERR_NOT_SUPPORTED_FUNC = 209,
|
ERR_WAFER_OUT = 210,
|
ERR_WAFER_SLIP = 211,
|
OVER_WAFER_DURING_GET = 212,
|
ERR_PLATE_CHECK = 213,
|
ERR_PUSHER_SPEED_HIGH = 214,
|
ERR_NOT_CORRECT_BLADE_POS = 241,
|
ERR_MAPPING_IS_NOT_PERFORMED = 251,
|
ERR_NO_MAPPING_DATA = 252,
|
ALREADY_LATCH_BLOCKED = 253,
|
ERR_CANNOT_UNGRIP = 300,
|
ERR_INVALID_COMMAND = 301,
|
ERR_INVALID_DATA = 311,
|
ERR_INVALID_STATION = 312,
|
ERR_INVALID_HAND = 313,
|
ERR_INVALID_SLOT = 314,
|
ERR_INVALID_TEACHING_INDEX = 315,
|
ERR_INVALID_PD_INDEX = 316,
|
ERR_INVALID_HAND_TYPE = 317,
|
ERR_BOX_NOEXIT_ERORR = 318,
|
ERR_INVALID_OFFSET = 319,
|
ERR_INVALID_COORDINATE_TYPE = 321,
|
ERR_INVALID_ARGUMENT = 331,
|
ERR_INVALID_FORMAT = 333,
|
ERR_INVALID_LOCATION_FORMAT = 334,
|
ERR_INVALID_PROFILE_FORMAT = 335,
|
ERR_WRONG_PD_COMMAND = 341,
|
ERR_WRONG_AWC_DATA = 342,
|
ERR_NO_AWC_STATION = 343,
|
ERR_WRONG_LATCH_DATA = 344,
|
ERR_NO_LATCH_DATA = 345,
|
ERR_NO_DATA = 351,
|
ERR_NOT_HOME = 352,
|
ERR_CANNOT_RETRACT_ARM = 353,
|
ERR_VACUUM_DETECTING_ERORR = 354,
|
ERR_NO_BOX = 355,
|
ERR_UPGRIP = 356,
|
ERR_DOUBLEBOXCHECH = 357,
|
ERR_ORIGINMANUALLY = 359,
|
ERR_NOTSUPPLY_AIR = 360,
|
ERR_NOW_ON_MOVE = 371,
|
ERR_NOT_READYPOS = 361,
|
Z_POSITION_ERR_DETECTED = 372,
|
ERR_FLIP_TURN_INTERLOCK = 378,
|
ERR_CONTROL_BOX_FAN = 380,
|
ERR_ROBOT_FAN = 381,
|
ERR_AIRSTOP_ERROR = 400,
|
ERR_RECEIVEBUF_FULL = 401,
|
ERR_SENDBUF_FULL = 402,
|
IO_RECEIVE_ERROR = 403,
|
}
|
}
|