using System.Text; using System.Collections.Generic; using System.Diagnostics; using Venus_RT.Modules; using MECF.Framework.Common.Communications; using MECF.Framework.Common.Equipment; using Venus_Core; using Aitex.Core.RT.SCCore; using Aitex.Core.RT.Event; using Aitex.Core.RT.Device; using Aitex.Core.RT.Log; using Aitex.Core.Util; using EPD.Data; namespace Venus_RT.Devices.EPD { class EPDClient : IDevice { public enum EDPStatus { Idle, Running, Error, } private EPDSocketClient _socketClient; private string _ip; private int _port; private int _channel; private Stopwatch _heartBeatTimer = new Stopwatch(); private bool _isHeartBeatReceived; private readonly R_TRIG _epdIdle = new R_TRIG(); public bool Captured { get; private set; } public bool IsEPDConnected { get; private set; } public EDPStatus Status { get; private set; } public List CFGFileList { get; private set; } public string Module { get; set; } public string Name { get; set; } public string EPDVersion { get; private set; } public string EPDState { get; private set; } public string SensorStatus { get; private set; } public string EPDRunStatus { get; private set; } public string EPDMode { get; private set; } public EPDClient(ModuleName mod) { Name = VenusDevice.EndPoint.ToString(); Module = mod.ToString(); _ip = ""; _port = 123; _channel = 0; _socketClient = new EPDSocketClient(); _socketClient.OnConnect += OnConnect; _socketClient.OnDisconnect += OnDisConnect; _socketClient.OnSocketSend += OnEPDSocketSend; _socketClient.OnSocketReceive += OnEPDSocketReceive; _socketClient.OnEPDReply += OnEPDReply; _socketClient.OnError += OnError; } public bool Initialize() { _socketClient.Connect(_ip, _port); _socketClient.ConnectEPD(); _socketClient.SetMode(2); // 1 local; 2 remote _socketClient.SetRunStatus(3); // 1 Monitor; 2 Save; 3:Capture; 4:Process _socketClient.QueryConfigList(); return true; } public void Monitor() { HeartBeat(); } public void Reset() { } public void Terminate() { Status = EDPStatus.Idle; _socketClient.DisconnectEPD(); _socketClient.Disconnect(); } public void RecipeStart() { _socketClient.RecipeStart(_channel, ""); Status = EDPStatus.Running; } public void RecipeStop() { _socketClient.RecipeStop(_channel); Status = EDPStatus.Idle; } public void StepStart(string cfgName) { _socketClient.Start((byte)_channel, cfgName); Status = EDPStatus.Running; } public void StepStop() { _socketClient.Stop((byte)_channel); } private void HeartBeat() { _epdIdle.CLK = Status == EDPStatus.Idle; if (_epdIdle.Q) { _socketClient.SendHeartBeat(); _heartBeatTimer.Restart(); _isHeartBeatReceived = false; } else if(_epdIdle.M) { if(_heartBeatTimer.ElapsedMilliseconds > 30000) { if (!_isHeartBeatReceived) { LOG.Write(eEvent.ERR_ENDPOINT, Module, "HeartBeat Error, EndPoint Device did not response in 5 seconds"); } _socketClient.SendHeartBeat(); _heartBeatTimer.Restart(); _isHeartBeatReceived = false; } } else { _heartBeatTimer.Stop(); } } private void OnConnect() { LOG.Write(eEvent.INFO_ENDPOINT, Module, "Endpoint connected"); } private void OnDisConnect() { LOG.Write(eEvent.INFO_ENDPOINT, Module, "Endpoint disconnected"); } private void OnEPDSocketReceive(string type, byte[] data, int length) { var content = StringJoin(" ", data, length); LOG.Write(eEvent.INFO_ENDPOINT, Module, $"Endpoint Receive: {content}"); } private void OnEPDSocketSend(string type, byte[] data) { var content = StringJoin(" ", data, data.Length); LOG.Write(eEvent.INFO_ENDPOINT, Module, $"Endpoint Send: {content}"); } private void OnError(int command, int errorCode) { var strError = errorCode.ToString(); if (EPDDefine.ErrorMap.ContainsKey(errorCode)) strError = EPDDefine.ErrorMap[errorCode]; string ErrorInfo = $"EndPoint Command {(EPDCommand)command} Failed: {strError}"; LOG.Write(eEvent.ERR_ENDPOINT, Module, ErrorInfo); } private void OnEPDReply(EPDCommand cmd, object obj) { switch (cmd) { case EPDCommand.SetWaferInfo: break; case EPDCommand.QueryCfgList: if (obj is List) CFGFileList = (List)obj; break; case EPDCommand.QueryState: if (obj is ushort state && EPDDefine.StateMap.ContainsKey(state)) EPDState = EPDDefine.StateMap[state]; break; case EPDCommand.QueryVer: EPDVersion = obj.ToString(); break; case EPDCommand.Connect: IsEPDConnected = true; break; case EPDCommand.HeartBeat: _isHeartBeatReceived = true; break; case EPDCommand.QueryRunStatus: if (obj is ushort sta && EPDDefine.RunStatusMap.ContainsKey(sta)) { EPDRunStatus = EPDDefine.RunStatusMap[sta]; } break; case EPDCommand.QueryOperateMode: if (obj is ushort mode && EPDDefine.ModeMap.ContainsKey(mode)) { EPDMode = EPDDefine.ModeMap[mode]; } break; case EPDCommand.GetSensorStatus: if (obj is List statusLst && statusLst.Count >= 2) { SensorStatus = statusLst[0]; } break; case EPDCommand.GetRecipesList: if (obj is List objs) { CFGFileList = objs.GetRange(3, objs.Count - 3); SensorStatus = objs[0]; } break; case EPDCommand.Event: var lst = obj as List; if (lst[0] is int type && type == 7) Captured = true; break; case EPDCommand.AsciiEvent: if (obj.ToString() == "ENDPOINT") Captured = true; break; case EPDCommand.QueryChannelCount: case EPDCommand.QueryChannalNames: case EPDCommand.RecipeStart: case EPDCommand.RecipeStop: case EPDCommand.Start: case EPDCommand.Stop: default: break; } } private string StringJoin(string separator, byte[] values, int length) { if (values == null || values.Length == 0) return string.Empty; if (separator == null) separator = string.Empty; var sb = new StringBuilder($"{values[0]:X2}"); for (int i = 1; i < length; i++) sb.Append($"{separator}{values[i]:X2}"); return sb.ToString(); } } }