using System; using System.Collections.Generic; using System.Linq; using System.Security; using System.ServiceModel; using System.Text; using Aitex.Core.RT.DataCenter; using Aitex.Core.RT.Device; using Aitex.Core.RT.Event; using Aitex.Core.RT.Log; using Aitex.Core.RT.OperationCenter; using Aitex.Core.RT.SCCore; using Aitex.Core.Util; using Aitex.Core.WCF; using EPInterface; using EPInterface.Data; using EPInterface.Datas; namespace Aitex.RT.Device.Custom { public class EPDDevice : BaseDevice, IDevice { private PeriodicJob _monitorThead; private R_TRIG _triggerConnected = new R_TRIG(); private R_TRIG _triggerNotConnected = new R_TRIG(); private int _channel; private string _channelStatus; //private bool _enableRetry = true; private object _lockerTrigger = new object(); private bool _isEnd = false; public bool IsEnd { get { return _isEnd; } } public bool IsConnected { get { return _triggerConnected.M; } } //private bool _isRecipeStarted; //private bool _isStepStarted; private int _connectionCounter = 0; public EPDDevice(string module, string name) : base(module, name, name, name) { } public bool Initialize() { _channel = SC.GetValue($"{Module}.{Name}.ChannelNumber"); DATA.Subscribe($"{Module}.{Name}.IsConnected", ()=> IsConnected); DATA.Subscribe($"{Module}.{Name}.CurrentChannel", () => _channel); DATA.Subscribe($"{Module}.{Name}.ChannelStatus", () => _channelStatus); OP.Subscribe($"{Module}.{Name}.SetConfig", (out string reason, int time, object[] args) => { if (!IsConnected) { EV.PostWarningLog(Module, $"{Module} {Name} not connected, can not set config"); reason = $"{Module} {Name} not connected, can not set config"; return false; } _isEnd = false; StepStart(args[1].ToString(), Convert.ToInt32(args[0])); reason = ""; return true; }); _monitorThead = new PeriodicJob(100, OnTimer, "EPDMonitor", true); EPDCallbackClient.Instance.Notify += Instance_Notify; EPDCallbackClient.Instance.Trigger += Instance_Trigger; return true; } public void RecipeStart(string recipeName) { if (!IsConnected) { LOG.Write("EPD not connected, call recipe start ignored"); return; } EV.PostInfoLog(Module, $"{Module} {Name}, Notify EPD recipe {recipeName} start"); EPDClient.Instance.Service.RecipeStart(_channel, recipeName); } public void RecipeStop() { if (!IsConnected) { LOG.Write("EPD not connected, call recipe start ignored"); return; } EV.PostInfoLog(Module, $"{Module} {Name}, Notify EPD recipe stopped"); EPDClient.Instance.Service.RecipeStop(_channel); } /* * ExposureTime=222;WaveLengthA=2;BinningA=3;WaveLengthB=4;BinningB=6;WaveLengthC=5;BinningC=8; * WaveLengthD=7;BinningD=9;Fd=1;PrefilterTime=2;PostfilterTime=3;AlgorithmType=Valley; * Criteria=4;DelayTime=5;ValidationTime=6;ValidationValue=7; * TimeWindow=8;MinimalTime=9;PostponeTime=10;Control=11;Normalization=12; * EnablePostponePercent=True;EnableCriterialPercent=True; * TriggerMode=System.Windows.Controls.ComboBoxItem: Event;IsFaultIfNoTrigger=True; */ public void StepStart(string config, int index) { if (!IsConnected) { LOG.Write("EPD not connected, call step start ignored"); return; } EV.PostInfoLog(Module, $"{Module} {Name}, Notify EPD recipe step {index+1} start"); EV.PostInfoLog(Module, $"{Module} {Name}, EPD config {config}"); try { EPDConfig epd = new EPDConfig(); epd.nParameterCount = 1; string[] items = config.Split(';'); foreach (var item in items) { if (string.IsNullOrEmpty(item)) continue; string[] pairs = item.Split('='); if (pairs.Length != 2) continue; switch (pairs[0]) { case "ExposureTime": epd.Columns[0].nCCDExposureTime = int.Parse(pairs[1]); break; case "WaveLengthA": epd.Columns[0].nWaveLength[0] = ushort.Parse(pairs[1]); break; case "BinningA": epd.Columns[0].nBinning[0] = ushort.Parse(pairs[1]); break; case "WaveLengthB": epd.Columns[0].nWaveLength[1] = ushort.Parse(pairs[1]); break; case "BinningB": epd.Columns[0].nBinning[1] = ushort.Parse(pairs[1]); break; case "WaveLengthC": epd.Columns[0].nWaveLength[2] = ushort.Parse(pairs[1]); break; case "BinningC": epd.Columns[0].nBinning[2] = ushort.Parse(pairs[1]); break; case "WaveLengthD": epd.Columns[0].nWaveLength[3] = ushort.Parse(pairs[1]); break; case "BinningD": epd.Columns[0].nBinning[3] = ushort.Parse(pairs[1]); break; case "Fd": epd.Columns[0].cFunc = pairs[1]; break; case "PrefilterTime": epd.Columns[0].nPreFilterTime = int.Parse(pairs[1]); break; case "PostfilterTime": epd.Columns[0].nPostFilterTime = int.Parse(pairs[1]); break; case "AlgorithmType": epd.Columns[0].algorithmType = MapType(pairs[1]); break; case "Criteria": epd.Columns[0].nCriteria = float.Parse(pairs[1]); break; case "DelayTime": epd.Columns[0].nDelayTime = int.Parse(pairs[1]); break; case "ValidationTime": epd.Columns[0].nValidationTime = int.Parse(pairs[1]); break; case "ValidationValue": epd.Columns[0].nValidationValue = int.Parse(pairs[1]); break; case "TimeWindow": epd.Columns[0].nTimeWindow = int.Parse(pairs[1]); break; case "MinimalTime": epd.Columns[0].nMinimalTime = int.Parse(pairs[1]); break; case "PostponeTime": epd.Columns[0].nPostponeTime = int.Parse(pairs[1]); break; case "Control": epd.Columns[0].bControl = Convert.ToBoolean(pairs[1]); break; case "Normalization": epd.Columns[0].bNormalization = Convert.ToBoolean(pairs[1]); break; case "EnablePostponePercent": epd.Columns[0].bPostponePercent = Convert.ToBoolean(pairs[1]); break; case "EnableCriterialPercent": epd.Columns[0].bCriteriaPercent = Convert.ToBoolean(pairs[1]); break; case "EnableEventTrigger": epd.Columns[0].bEvtTrigger = Convert.ToBoolean(pairs[1]); break; } } EPDClient.Instance.Service.StartByConfig(_channel, index, $"step{index}", epd); } catch (Exception ex) { LOG.Write(ex); EV.PostInfoLog(Module, $"{Module} {Name}, Step {index + 1} config values not valid, {ex.Message}"); } } private AlgorithmType MapType(string type) { switch (type) { case "Unknown": return AlgorithmType.ALG_NONE; case "Above_ABS_Value": return AlgorithmType.ALG_RISE_VALUE; case "Below_ABS_Value": return AlgorithmType.ALG_FALL_VALUE; case "Drop_Percent": return AlgorithmType.ALG_FALL_PERCENT; case "Up_Percent": return AlgorithmType.ALG_RISE_PERCENT; case "Range_In": return AlgorithmType.ALG_RANGE_IN; case "Gradient": return AlgorithmType.ALG_GRADIENT; case "Peek": return AlgorithmType.ALG_PEAK; case "Valley": return AlgorithmType.ALG_VALLEY; case "Min_Drop_Percent": return AlgorithmType.ALG_MIN_FALL_PERCENT; case "Min_Up_Percent": return AlgorithmType.ALG_MIN_RISE_PERCENT; case "Max_Drop_Percent": return AlgorithmType.ALG_MAX_FALL_PERCENT; case "Max_Up_Percent": return AlgorithmType.ALG_MAX_RISE_PERCENT; case "Rise_Fall": return AlgorithmType.ALG_RISE_FALL; case "Fall_Rise": return AlgorithmType.ALG_FALL_RISE; } return AlgorithmType.ALG_NONE; } public void StepStop() { if (!IsConnected) { LOG.Write("EPD not connected, call step stop ignored"); return; } EV.PostInfoLog(Module, $"{Module} {Name}, Notify EPD recipe step stopped"); EPDClient.Instance.Service.Stop(_channel); } private bool OnTimer() { try { bool retryConnect = false; lock (_lockerTrigger) { retryConnect = _triggerConnected.M; if (!_triggerConnected.M) { //if (_enableRetry) { retryConnect = true; //_enableRetry = false; } } if (retryConnect) { _connectionCounter++; if (_connectionCounter > 10000) _connectionCounter = 1; _triggerConnected.CLK = _connectionCounter== EPDClient.Instance.Service.Heartbeat(_connectionCounter); _triggerNotConnected.CLK = !_triggerConnected.M; if (_triggerConnected.Q) { EPDCallbackClient.Instance.Init(); EV.PostInfoLog(Module, $"{Module} {Name}, EPD Connected"); } if (_triggerConnected.M) { _channelStatus = EPDClient.Instance.Service.QueryState(_channel).ToString(); } if (_triggerNotConnected.Q) { EPDCallbackClient.Instance.Stop(); EV.PostWarningLog(Module, $"{Module} {Name}, EPD disconnected"); } } } } catch (Exception ex) { LOG.Write(ex); } return true; } private void Instance_Notify(int channel, string e) { if (_channel != channel) return; EV.PostInfoLog(Module, $"{Module} {Name}, EPD Feedback:{e}"); } private void Instance_Trigger(int channel, TriggerEventArgs e) { if (_channel != channel) return; _isEnd = true; EV.PostInfoLog(Module, $"{Module} {Name}, EPD: {e.Channel}.{e.Name} Triggered"); } public void Monitor() { } public void Terminate() { } public void Reset() { lock (_lockerTrigger) { if (!_triggerConnected.M) { //_enableRetry = true; _triggerConnected.RST = true; _triggerNotConnected.RST = true; } } } } public class EPDCallbackClient : Singleton, IEPDCallback { public event Action Notify; public event Action Trigger; private EPDCallbackServiceClient _service; public EPDCallbackClient() { _service = new EPDCallbackServiceClient(this); } public void Init() { _service.Register(); } public void Stop() { _service.UnRegister(); } //public void OnNotify(string channel, string message) //{ //} //public void OnTrigger(string channel, string name, long ticket) //{ //} public void OnNotify(int channel, EPDEventType EventType, string message) { Notify?.Invoke(channel, $"{EventType}:{message}"); } public void OnTrigger(int channel, string name, long ticket) { Trigger?.Invoke(channel, new TriggerEventArgs() { Channel = channel, Name = name, Ticket = ticket }); } } public class TriggerEventArgs { public int Channel { get; set; } public string Name { get; set; } public long Ticket { get; set; } } public class EPDCallbackServiceClient : DuplexChannelServiceClientWrapper { private Guid _clientId = Guid.Empty; public EPDCallbackServiceClient(IEPDCallback callback) : base(new InstanceContext(callback), "Client_IEPDCallbackService", "IEPDCallbackService") { } public void Register() { if (_clientId != Guid.Empty) UnRegister(); _clientId = Guid.NewGuid(); Invoke(x => x.Register(_clientId)); } public void UnRegister() { Invoke(x => x.UnRegister(_clientId)); } } }