using System; using System.Collections.Generic; using System.Text.RegularExpressions; using System.Threading; using System.Threading.Tasks; using Aitex.Core.Util; using MECF.Framework.Simulator.Core.Driver; namespace EfemDualSimulator.Devices { class EfemSimulatorServer : SocketDeviceSimulator { private const string CMD_PATTERN = "^MOV|^SET|^GET"; private const string SCMD = @"(?<=\:)(.*?)(?=\/)"; private const string SFOUP = @"(?<=P)(\d{1})(?=[\;\/])"; private const string ACK = "ACK"; private string[] _slotMap = new string[25]; private PeriodicJob _HwThread; private bool _bCommReady; private bool _isDoorOpen; private bool _isPlaced; public int WaferSize = 3; public string SlotMap { get { return string.Join("", _slotMap); } } public bool _isVacuumError { get; set; } public bool _isAirError { get; set; } public bool _isFlowError { get; set; } public bool _isLeak { get; set; } public bool _isMaintain { get; set; } public bool _isWaferPresent { get; set; } public bool _isMaintainDoorOpen { get; private set; } public bool _isProtrude1 { get; set; } public bool _isProtrude2 { get; set; } public EfemSimulatorServer() : base(13000, -1, "\r", ' ') { for (int i = 0; i < _slotMap.Length; i++) _slotMap[i] = "0"; _HwThread = new PeriodicJob(5000, OnSendEvent, "EfemHardware", true); } private bool OnSendEvent() { if (!_bCommReady) { OnWriteMessage("INF:READY/COMM;"); } return true; } protected override void ProcessUnsplitMessage(string str) { if (!_bCommReady && str.Contains("ACK:READY/COMM")) { _bCommReady = true; } if (!Regex.IsMatch(str, CMD_PATTERN)) return; // 发送ACK 表示收到 string ack = Regex.Replace(str, CMD_PATTERN, ACK); OnWriteMessage(ack); // 处理INF var a = OnWork(ack); } internal void SetCassetteDoor(bool doorOpen) { if (doorOpen != _isDoorOpen) { _isDoorOpen = doorOpen; SendSystemData(); } } internal void SetMaintain(bool maintain) { if (maintain != _isMaintain) { _isMaintain = maintain; SendSystemData(); } } internal void SetProtrude1(bool protrude) { if (protrude != _isProtrude1) { _isProtrude1 = protrude; SendLP1Data(); } } internal void SetProtrude2(bool protrude) { if (protrude != _isProtrude2) { _isProtrude2 = protrude; SendLP2Data(); } } private async Task OnWork(string strACK) { // match basic Match m1 = Regex.Match(strACK, SCMD); // get mock delay time string sBasic = m1.Groups[1].Value; if (string.IsNullOrEmpty(sBasic)) return; EfemOperation op = EfemConstant.ToOperation(sBasic); ushort millionSec = this.SimuOperationTime(op); // Sleep await Task.Run(() => Thread.Sleep(millionSec)); // build the INF string string strINF = string.Empty; switch (EfemConstant.ToOperation(sBasic)) { case EfemOperation.GetWaferInfo: strINF = strACK.Replace(ACK, "INF"); strINF = strINF.TrimEnd(';'); strINF += "/1111111111111110001111111;"; break; case EfemOperation.Home: //string s1 = "EVT:SIGSTAT/P1/00000381/00000000;\rEVT:SIGSTAT/P2/00000381/00000000;\rEVT:SIGSTAT/System/0000FFF7/00000004;\r"; //strINF = s1 + strACK.Replace(ACK, "INF"); SendSystemData(); SendLP1Data(); SendLP2Data(); return; case EfemOperation.Map: Match m2 = Regex.Match(strACK, SFOUP); if (m2.Success) { string map = string.Join("", _slotMap); string s2 = $"EVT:MAPDT/P{m2.Groups[1].Value}/{map};\r"; strINF = s2 + strACK.Replace(ACK, "INF"); } break; case EfemOperation.Align: case EfemOperation.Pick: case EfemOperation.Place: case EfemOperation.Orgsh: case EfemOperation.Light: case EfemOperation.SigStatus: default: strINF = strACK.Replace(ACK, "INF"); break; } OnWriteMessage(strINF); } private void SendLP1Data() { uint data = GetLP1Data1(); string msg = $"EVT:SIGSTAT/P1/{data:X8}/00000000;"; OnWriteMessage(msg); } private void SendLP2Data() { uint data = GetLP2Data1(); string msg = $"EVT:SIGSTAT/P2/{data:X8}/00000000;"; OnWriteMessage(msg); } private void SendSystemData() { uint data = GetSystemData1(); string msg = $"EVT:SIGSTAT/System/{data:X8}/00000000;"; OnWriteMessage(msg); } private ushort SimuOperationTime(EfemOperation op) { ushort sec = 0; switch (op) { case EfemOperation.Map: case EfemOperation.GetWaferInfo: case EfemOperation.Align: sec = 300; break; case EfemOperation.Pick: case EfemOperation.Place: case EfemOperation.Orgsh: sec = 400; break; case EfemOperation.Light: case EfemOperation.SigStatus: sec = 200; break; default: sec = 100; break; } return sec; } public void PlaceCarrier1() { _isPlaced = true; SendLP1Data(); } public void RemoveCarrier1() { _isPlaced = false; SendLP1Data(); } public void PlaceCarrier2() { _isPlaced = true; SendLP2Data(); } public void RemoveCarrier2() { _isPlaced = false; SendLP2Data(); } public void ClearWafer() { for (int i = 0; i < _slotMap.Length; i++) { _slotMap[i] = "0"; } } public void SetAllWafer() { for (int i = 0; i < _slotMap.Length; i++) { _slotMap[i] = "1"; } } public void SetUpWafer() { for (int i = 0; i < _slotMap.Length; i++) { _slotMap[i] = i > 15 ? "1" : "0"; } } public void SetLowWafer() { for (int i = 0; i < _slotMap.Length; i++) { _slotMap[i] = i < 10 ? "1" : "0"; } } public void RandomWafer() { Random _rd = new Random(); for (int i = 0; i < _slotMap.Length; i++) { _slotMap[i] = (i % 9).ToString();// _rd.Next(0, 10) < 6 ? "0" : "1"; } } private uint GetLP1Data1() { uint data1 = 0x0u; data1 |= (_isPlaced ? 0x00000001u : 0x0); data1 |= (!_isPlaced ? 0x00000002u : 0x0); switch (WaferSize) { case 3: //data1 |= 0x00000040u; data1 |= 0x00000080u; data1 |= 0x00000100u; break; case 4: data1 |= 0x00000040u; //data1 |= 0x00000080u; data1 |= 0x00000100u; break; case 6: data1 |= 0x00000040u; data1 |= 0x00000080u; //data1 |= 0x00000100u; break; } data1 |= (!_isProtrude1) ? 0x00000200u : 0x0; return data1; } private uint GetLP2Data1() { uint data1 = 0x0u; data1 |= (_isPlaced ? 0x00000001u : 0x0); data1 |= (!_isPlaced ? 0x00000002u : 0x0); switch (WaferSize) { case 3: //data1 |= 0x00000040u; data1 |= 0x00000080u; data1 |= 0x00000100u; break; case 4: data1 |= 0x00000040u; //data1 |= 0x00000080u; data1 |= 0x00000100u; break; case 6: data1 |= 0x00000040u; data1 |= 0x00000080u; //data1 |= 0x00000100u; break; } data1 |= (!_isProtrude2) ? 0x00000200u : 0x0; return data1; } private uint GetSystemData1() { uint data1 = 0x0u; //0: data1 |= (!_isVacuumError ? 0x00000001u : 0x0); //3: data1 |= (!_isAirError ? 0x00000004u : 0x0); //4 Flow gauge Sensor Warning data1 |= (_isFlowError ? 0x00000010u : 0x0); //5 Leakage Sensor Warning data1 |= (_isLeak ? 0x00000020u : 0x0); //6:Door switch Door close data1 |= (!_isMaintainDoorOpen ? 0x00000040u : 0x0); //7 Drive power Normal data1 |= 0x00000080u; //8 Differential pressure sensor setting 1 Normal data1 |= 0x00000100u; //9 Differential pressure sensor setting 1 Normal data1 |= 0x00000200u; //10 Ionizer alarm Normal data1 |= 0x00000400u; //11 FFU alarm Normal data1 |= 0x00000800u; //12 Area sensor(Reserved) Not blocked data1 |= 0x00001000u; //13 Mode switch RUN data1 |= (!_isMaintain ? 0x00002000u : 0x0); //14 Robot Wafer Present No presence data1 |= (!_isWaferPresent ? 0x00004000u : 0x0); //15 Cassette Door Door Closed data1 |= (!_isDoorOpen ? 0x00008000u : 0x0); return data1; } } public class DeviceName { //Eefem public const string EfemRobot = "EfemRobot"; } public enum EfemOperation { Home, //HomeLP, Pick, Place, Goto, Extend, Retract, Align, Map, Light, TurnOffBuzzer, //SwitchOnBuzzerAndRed, GetWaferInfo, Orgsh, Lift, SigStatus, Ready, Abort, ClearError, PmPinUp, PmPinDown } public class EfemConstant { public static readonly Dictionary OperationString = new Dictionary() { { EfemOperation.Ready, "READY" }, { EfemOperation.Home, "INIT" }, { EfemOperation.Orgsh, "ORGSH" }, { EfemOperation.ClearError, "ERROR"}, //{ EfemOperation.HomeLP, "INIT" }, { EfemOperation.Map, "WAFSH" }, { EfemOperation.GetWaferInfo, "MAPDT" }, { EfemOperation.Pick, "LOAD" }, { EfemOperation.Place, "UNLOAD" }, { EfemOperation.Extend, "MPNT" }, { EfemOperation.Align, "ALIGN" }, { EfemOperation.SigStatus, "SIGSTAT" }, { EfemOperation.Lift, "LIFT" }, { EfemOperation.Light, "SIGOUT" }, { EfemOperation.Abort, "ABORT" }, { EfemOperation.Goto, "GOTO" }, }; public static EfemOperation ToOperation(string str) { foreach (var item in OperationString) { if (item.Value == str) { return item.Key; } } throw new ApplicationException($"Cannot translate {str}"); } } }