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 MECF.Framework.Common.Communications; using System; using System.Collections.Generic; using System.Diagnostics; using System.Threading; using System.Threading.Tasks; namespace MECF.Framework.RT.EquipmentLibrary.HardwareUnits.EndPoints.CytEndPoints { [Serializable] public class CytEndPoint : BaseDevice, IDevice { public event Action OnError; public event Action OnEPDTrigger; public string Address => Connection?.Address; public bool IsConnected => Connection != null && Connection.IsConnected && !_connection.IsCommunicationError; public bool Connect() { return _connection.Connect(); } public bool Disconnect() { return _connection.Disconnect(); } public byte SlaveAddress { get; private set; } = 0x01; public string PortStatus { get; set; } = "Closed"; private CytEndPointConnection _connection; public CytEndPointConnection Connection { get { return _connection; } } public List ConfigList { get { GetConfigList(); return _configs; } } public bool IsTrigger { get; set; } private R_TRIG _trigError = new R_TRIG(); private R_TRIG _trigCommunicationError = new R_TRIG(); private R_TRIG _trigRetryConnect = new R_TRIG(); private PeriodicJob _thread; private LinkedList _lstHandler = new LinkedList(); private LinkedList _lstMonitorHandler = new LinkedList(); private object _locker = new object(); private bool _enableLog; private string _address; private string _scRoot; private string _currentConfigName; private string _status; private List _trendName; private double[] _trendValue; private double[] _spectrum; private double[] _magnitude; private bool _isEPDConnected; private string _errorInfo; private string _epdState; private string _epdMode; private bool _isRemote; private List _configs = new List(); private Stopwatch _runningTimer = new Stopwatch(); public CytEndPoint(string module, string name, string scRoot) : base() { _scRoot = scRoot; base.Module = module; base.Name = name; _status = "Unconnected"; _currentConfigName = "--"; } public bool Initialize() { _address = SC.GetStringValue($"{_scRoot}.Address"); _enableLog = SC.GetValue($"{_scRoot}.EnableLogMessage"); _connection = new CytEndPointConnection(_address); _connection.EnableLog(_enableLog); _connection.SetEventHandler(new CytEventHandler(this)); _lstHandler.AddLast(new CytConnectHandler(this)); _lstHandler.AddLast(new CytQueryConfigListHandler(this)); if (_connection.Connect()) { PortStatus = "Open"; EV.PostInfoLog(Module, $"{Module}.{Name} connected"); } DATA.Subscribe($"{Module}.{Name}.IsConnected", () => IsConnected); DATA.Subscribe($"{Module}.{Name}.Address", () => Address, SubscriptionAttribute.FLAG.IgnoreSaveDB); DATA.Subscribe($"{Module}.{Name}.IsTrigger", () => IsTrigger); DATA.Subscribe($"{Module}.{Name}.TrendName", () => _trendName, SubscriptionAttribute.FLAG.IgnoreSaveDB); DATA.Subscribe($"{Module}.{Name}.TrendValue", () => _trendValue, SubscriptionAttribute.FLAG.IgnoreSaveDB); DATA.Subscribe($"{Module}.{Name}.Spectrum", () => _spectrum, SubscriptionAttribute.FLAG.IgnoreSaveDB); DATA.Subscribe($"{Module}.{Name}.Magnitude", () => _magnitude, SubscriptionAttribute.FLAG.IgnoreSaveDB); DATA.Subscribe($"{Module}.{Name}.ConfigList", () => ConfigList, SubscriptionAttribute.FLAG.IgnoreSaveDB); DATA.Subscribe($"{Module}.{Name}.CurrentConfigName", () => _currentConfigName, SubscriptionAttribute.FLAG.IgnoreSaveDB); DATA.Subscribe($"{Module}.{Name}.Status", () => _epdState, SubscriptionAttribute.FLAG.IgnoreSaveDB); DATA.Subscribe($"{Module}.{Name}.IsRunning", () => _runningTimer.IsRunning); OP.Subscribe($"{Module}.{Name}.Reconnect", (string cmd, object[] args) => { Disconnect(); Reset(); Connect(); return true; }); OP.Subscribe($"{Module}.{Name}.ManualEndPoint", (string cmd, object[] args) => { return true; }); OP.Subscribe($"{Module}.{Name}.EPDConfigName", (out string reason, int time, object[] param) => { reason = string.Empty; string config = param[0].ToString(); Start(config); EV.PostInfoLog(Module, $"Set EPD config name {config}"); return true; }); OP.Subscribe($"{Module}.{Name}.Stop", (string cmd, object[] args) => { Stop(); return true; }); OP.Subscribe($"{Module}.{Name}.RecipeStart", (string cmd, object[] args) => { RecipeStart(); return true; }); OP.Subscribe($"{Module}.{Name}.RecipeStop", (string cmd, object[] args) => { RecipeStop(); return true; }); _thread = new PeriodicJob(300, OnTimer, $"{Module}.{Name} MonitorHandler", true); return true; } Random _rd = new Random(); Stopwatch _sw = new Stopwatch(); private bool OnTimer() { try { if (!_connection.IsConnected || _connection.IsCommunicationError) { lock (_locker) { _lstHandler.Clear(); } _trigRetryConnect.CLK = !_connection.IsConnected; if (_trigRetryConnect.Q) { if (!_connection.Connect()) { EV.PostAlarmLog(Module, $"Can not connect with {_connection.Address}, {Module}.{Name}"); } else { _lstHandler.AddLast(new CytConnectHandler(this)); _lstHandler.AddLast(new CytQueryConfigListHandler(this)); } } return true; } HandlerBase handler = null; if (!_connection.IsBusy) { lock (_locker) { if (_lstHandler.Count == 0) { foreach (var monitorHandler in _lstMonitorHandler) { _lstHandler.AddLast(monitorHandler); } } if (_lstHandler.Count > 0) { handler = _lstHandler.First.Value; _lstHandler.RemoveFirst(); } } if (handler != null) { _connection.Execute(handler); } } } catch (Exception ex) { LOG.Write(ex); } return true; } public void Monitor() { try { _connection.EnableLog(_enableLog); _trigCommunicationError.CLK = _connection.IsCommunicationError; if (_trigCommunicationError.Q) { EV.PostAlarmLog(Module, $"{Module}.{Name} communication error, {_connection.LastCommunicationError}"); } } catch (Exception ex) { LOG.Write(ex); } } public void Reset() { _trigError.RST = true; _connection.SetCommunicationError(false, ""); _trigCommunicationError.RST = true; _enableLog = SC.GetValue($"{_scRoot}.EnableLogMessage"); _trigRetryConnect.RST = true; } public void Terminate() { } internal void NoteIsConnected(bool isConnected) { _isEPDConnected = isConnected; } internal void NoteIsRemote(bool isRemote) { _isRemote = isRemote; } internal void NoteMode(string mode) { _epdMode = mode; } internal void NoteState(string state) { _epdState = state; } internal void NoteConfigList(List cfgList) { _configs = cfgList; } internal void NoteTrigger(long ticket) { EV.PostInfoLog(Module, $"Receive EndPoint notify: trigger ({ticket}) at {_runningTimer.ElapsedMilliseconds / 1000:F1} second"); IsTrigger = true; } internal void NoteStop(long ticket) { EV.PostInfoLog(Module, $"Receive EndPoint notify: stop at {_runningTimer.ElapsedMilliseconds / 1000:F1} second"); _runningTimer.Stop(); } internal void NoteSatisfied(long ticket) { EV.PostInfoLog(Module, $"Receive EndPoint notify: satisfied at {_runningTimer.ElapsedMilliseconds / 1000:F1} second"); } internal void NoteNormalizeStart(long ticket) { EV.PostInfoLog(Module, $"Receive EndPoint notify: normalize from {_runningTimer.ElapsedMilliseconds / 1000:F1} second"); } internal void NoteDelayEnd(long ticket) { EV.PostInfoLog(Module, $"Receive EndPoint notify: delay end at {_runningTimer.ElapsedMilliseconds / 1000:F1} second"); } internal void NoteStart(long ticket) { EV.PostInfoLog(Module, $"Receive EndPoint notify: start"); _runningTimer.Restart(); GetCurrentConfig(); } public string Error { get; private set; } private R_TRIG _trigWarningMessage = new R_TRIG(); public void NoteError(string reason) { if (!string.IsNullOrEmpty(reason)) { _trigWarningMessage.CLK = true; if (_trigWarningMessage.Q) { EV.PostWarningLog(Module, $"{Module}.{Name} error, {reason}"); } Error = reason; } else { Error = null; } } internal void NoteCurrentConfigIntegrationTime(int v) { } internal void NoteCurrentConfigName(string name) { _currentConfigName = name; } internal void NoteTrendName(List name) { _trendName = name; _trendValue = new double[name.Count]; } internal void NoteTrendValue(string data) { var value = data.Split(','); if (_trendValue != null) { for (int i = 0; i < value.Length && i < _trendValue.Length; i++) { if (string.IsNullOrEmpty(value[i])) { _trendValue[i] = 0.0; } else { _trendValue[i] = double.Parse(value[i]); } } } } public void GetCurrentConfig() { lock (_locker) { _lstHandler.AddLast(new CytQueryCurrentConfigHandler(this)); } var t1 = new Task(() => { bool isReturned = false; while (!isReturned) { lock (_locker) { bool done = true; foreach (var handlerBase in _lstHandler) { if (handlerBase is CytQueryCurrentConfigHandler) { done = false; break; } } isReturned = done; } if (!isReturned) Thread.Sleep(100); } }); t1.Start(); Task.WaitAll(new Task[] { t1 }, 5000); } public void GetConfigList() { lock (_locker) { _lstHandler.AddLast(new CytQueryConfigListHandler(this)); } var t1 = new Task(() => { bool isReturned = false; while (!isReturned) { lock (_locker) { bool done = true; foreach (var handlerBase in _lstHandler) { if (handlerBase is CytQueryConfigListHandler) { done = false; break; } } isReturned = done; } if (!isReturned) Thread.Sleep(100); } }); t1.Start(); Task.WaitAll(new Task[] { t1 }, 5000); } public void RecipeStart() { lock (_locker) { LOG.Write($"{Name} recipe start"); IsTrigger = false; _lstHandler.AddLast(new CytRecipeStartHandler(this)); } } public void RecipeStop() { lock (_locker) { LOG.Write($"{Name} recipe stop"); _lstHandler.AddLast(new CytRecipeStopHandler(this)); } } public void Start(string config) { lock (_locker) { LOG.Write($"{Name} start"); IsTrigger = false; _lstHandler.AddLast(new CytStartHandler(this, config)); } } public void Stop() { lock (_locker) { LOG.Write($"{Name} stop"); _lstHandler.AddLast(new CytStopHandler(this)); } } } }