using Aitex.Core.RT.Event; using Aitex.Core.RT.Log; using Aitex.Core.RT.SCCore; using Aitex.Core.Util; using MECF.Framework.Common.Communications; using MECF.Framework.Common.Event; using MECF.Framework.Common.PLC; using MECF.Framework.RT.Core.IoProviders.Siemens; using MECF.Framework.RT.EquipmentLibrary.HardwareUnits.OffsetManage; using System; using System.Collections.Generic; using System.Text.RegularExpressions; using System.Threading.Tasks; using System.Xml; namespace Aitex.Core.RT.Device.Devices { public class TcAds : BaseDevice, IConnectable, IConnectionContext, IDevice, IConnection, IAdsPlc { #region IConnectionContext public int RetryConnectIntervalMs => 1000; //这个属性是底层库重连次数,超过重连次数,以后不在重新连接 public int MaxRetryConnectCount => 5; public bool EnableCheckConnection => true; public virtual string Address { get; } public bool IsAscii { get; } public string NewLine { get; } public bool EnableLog { get; } private int MaxFailCount = 3; private int readPLCFailCount; private R_TRIG trig_readPLCFailCount = new R_TRIG(); private int writePLCFailCount; private R_TRIG trig_writePLCFailCount = new R_TRIG(); private R_TRIG trig_Reconnection = new R_TRIG(); private PeriodicJob _thread; #endregion IConnectionContext #region IConnectable public event Action OnCommunicationError; public event Action OnAsciiDataReceived; public event Action OnBinaryDataReceived; #endregion IConnectable public event Action OnDisconnected; bool IAdsPlc.CheckIsConnected() { return Connection.IsConnected; } bool IConnection.IsConnected { get { return Connection.IsConnected; } } bool IConnection.Connect() { Connect(out _); return true; } bool IConnection.Disconnect() { Disconnect(out _); return true; } public FsmConnection Connection { get; set; } = new FsmConnection(); //public bool IsCommunicationError //{ // get // { // return _isCommunicationError; // } //} //private bool _isCommunicationError; private OffsetManager offset; private OperateResult connect; public SiemensS7Net siemensTcpNet = null; private SiemensPLCS siemensPLCSelected = SiemensPLCS.S1500; private string _plcType; private Dictionary _nameHandleMap = new Dictionary(); private bool _isTargetConnected; public AlarmEventItem AlarmConnectFailed { get; set; } public AlarmEventItem AlarmCommunicationError { get; set; } public event Action OnConnected; public TcAds(string module, XmlElement node, string ioModule = "") { var attrModule = node.GetAttribute("module"); Module = string.IsNullOrEmpty(attrModule) ? module : attrModule; Name = node.GetAttribute("id"); Address = SC.GetStringValue($"PM.{Module}.SiemensIP"); _plcType = SC.GetStringValue($"PM.{Module}.SiemensType"); } public bool Initialize() { if (!SC.GetValue($"System.SetUp.Is{Module}Installed")) return true; offset = new OffsetManager(Module); AlarmConnectFailed = SubscribeAlarm($"{Module}.{Name}.ConnectionError", $"Can not connect with {Address}", null); AlarmCommunicationError = SubscribeAlarm($"{Module}.{Name}.CommunicationError", $"Can not Communication {Address}", null); Connection = new FsmConnection(); Connection.Initialize(100, this, this); Connection.OnConnected += Connection_OnConnected; Connection.OnDisconnected += Connection_OnDisconnected; Connection.OnError += Connection_OnError; ConnectionManager.Instance.Subscribe($"{Module}.{Name}", this); _thread = new PeriodicJob(2000, OnTimer, "PLC Reconnection Thread", false); return true; } bool IConnectable.CheckIsConnected() { return siemensTcpNet != null && siemensTcpNet.IsConnected; } public bool Connect(out string reason) { var ipAddr = ParseAdsIPAddr(Address); siemensPLCSelected = (SiemensPLCS)Enum.Parse(typeof(SiemensPLCS), _plcType); siemensTcpNet = new SiemensS7Net(siemensPLCSelected); siemensTcpNet.IpAddress = ipAddr.Item1;// _ipAddress; siemensTcpNet.Port = ipAddr.Item2; // int.Parse(_port); siemensTcpNet.ConnectTimeOut = 1; siemensTcpNet.ReceiveTimeOut = 1000; try { if (siemensPLCSelected != SiemensPLCS.S200Smart && siemensPLCSelected != SiemensPLCS.S200) { siemensTcpNet.Rack = 0; siemensTcpNet.Slot = 0; siemensTcpNet.ConnectionType = 1; siemensTcpNet.LocalTSAP = 258; } connect = siemensTcpNet.ConnectServer(); if (!siemensTcpNet.IsConnected) { //_isCommunicationError = true; //IsConnect = true; //EV.PostInfoLog(Module, "PLC Connection Successful!"); } else { //_isCommunicationError = false; } //return connect.IsSuccess; } catch (Exception ex) { _isTargetConnected = false; //_isCommunicationError = true; reason = ex.Message; return false; } _isTargetConnected = true; reason = string.Empty; return true; } public bool Disconnect(out string reason) { reason = string.Empty; siemensTcpNet.ConnectClose(); siemensTcpNet = null; connect = null; return false; } private void Connection_OnError(string obj) { AlarmConnectFailed.Set(); _thread.Start(); } private void Connection_OnDisconnected() { EV.PostInfoLog(Module, $"Disconnect from PLC {Address}"); _thread.Start(); ResetAlarm(); } private void Connection_OnConnected() { EV.PostInfoLog(Module, $"Connected with PLC {Address}"); EV.PostInfoLog(Module, $"Delay 5s can do offset"); Task.Delay(5000).ContinueWith(x => offset.Set()); ResetAlarm(); } protected override void HandleMonitor() { //Reconnection(); } public bool OnTimer() { Reconnection(); return true; } /// /// 事件触发线程启动,PLC断线延时2秒重连,连接后才会退出线程 /// protected void Reconnection() { try { if (siemensTcpNet == null || siemensTcpNet.IsConnected)//连接被主动切断,或者已连接直接退出 return; trig_Reconnection.CLK = true; if (trig_Reconnection.Q)//首次进去提示用户 EV.PostWarningLog(Module, "Disconnect from PLC,Stat reconnection"); connect = siemensTcpNet.ConnectServer(); if (siemensTcpNet.IsConnected) { trig_Reconnection.RST = true; Connection.InvokeReset(); EV.PostInfoLog(Module, "PLC reconnection successful!"); _thread.Stop(); } } catch { } } public void Terminate() { Connection.Terminate(); } private Tuple ParseAdsIPAddr(string addr) { if (addr == null) throw (new Exception("PM.SiemensIP is not exist in sc.data!")); Regex reg = new Regex(@"^((2[0-4]\d|25[0-5]|[01]?\d\d?)\.){3}(2[0-4]\d|25[0-5]|[01]?\d\d?):(\d{1,5})$"); if (!reg.IsMatch(addr)) throw (new Exception($@"{Module}.SiemensIP '{addr}' is invalid!")); var item = addr.Split(':'); return Tuple.Create(item[0], int.Parse(item[1])); } public void Reset() { ResetAlarm(); trig_Reconnection.RST = true;//复位重连trig信号 //复位读写异常trig信号 trig_readPLCFailCount.RST = true; trig_writePLCFailCount.CLK = true; Connection.InvokeReset(); } public bool Read(string variableName, out object data, string type, int length, out string reason) { data = null; reason = string.Empty; return true; } public bool WriteArrayElement(string variableName, int index, object data, out string reason) { reason = ""; return true; } public bool SendBinaryData(byte[] data) { return true; } public bool SendAsciiData(string data) { return true; } public bool BulkReadRenderResult(string Adrress, ushort length, out byte[] data) { try { if (siemensTcpNet == null || !siemensTcpNet.IsConnected) { data = null; return false; } OperateResult read = siemensTcpNet.Read(Adrress, length);// ushort.Parse(lengthTextBox.Text)); if (read.IsSuccess) { data = read.Content; //复位读错误次数 trig_readPLCFailCount.RST = true; readPLCFailCount = 0; return true; } else { //if (!_isCommunicationError) LOG.Write($"PLC BulkReadRenderResult Communication error with Siemens PLC , {read.Message}"); //_isCommunicationError = true; data = null; //新增读错误次数判断 if (readPLCFailCount < MaxFailCount) { readPLCFailCount++; } else { trig_readPLCFailCount.CLK = true; if (trig_readPLCFailCount.Q) { EV.PostWarningLog(Module, $"PLC BulkReadRenderResult error with Siemens PLC , {read.Message}"); } } return false; } } catch (Exception ex) { // EV.PostAlarmLog("", "Read Failed:" + ex.Message); } data = null; return false; } public bool BulkWriteByteRenderResult(string Adrress, byte[] data) { try { if (siemensTcpNet == null || !siemensTcpNet.IsConnected) { data = null; return false; } OperateResult write = siemensTcpNet.Write(Adrress, data); if (!write.IsSuccess) { //if (!_isCommunicationError) //EV.PostInfoLog("PLC", $"Communication error with Siemens PLC , {write.Message}"); LOG.Write($"PLC BulkWriteByteRenderResult Communication error with Siemens PLC , {write.Message}"); //_isCommunicationError = true; //新增写错误次数判断 if (writePLCFailCount < MaxFailCount) { writePLCFailCount++; } else { trig_writePLCFailCount.CLK = true; if (trig_writePLCFailCount.Q) { EV.PostWarningLog(Module, $"PLC BulkWriteByteRenderResult error with Siemens PLC , {write.Message}"); } } return false; } //复位写错误次数 trig_writePLCFailCount.RST = true; writePLCFailCount = 0; return write.IsSuccess; } catch (Exception ex) { // EV.PostAlarmLog("", "Read Failed:" + ex.Message); } return false; } } }