using Aitex.Core.RT.DataCenter; using Aitex.Core.RT.Event; using Aitex.Core.RT.IOCore; using Aitex.Core.RT.Log; using Aitex.Core.RT.OperationCenter; using Aitex.Core.RT.SCCore; using Aitex.Core.Util; using HslCommunication; using HslCommunication.ModBus; using MECF.Framework.Common.IOCore; using MECF.Framework.Common.PLC; using MECF.Framework.RT.Core.IoProviders; using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Xml; namespace FurnaceRT.Equipments.Systems { public class ModbusTCP : IoProvider { private string _address; private Int32 _port; private byte _station; public int _diStartAddress; public int _doStartAddress; public int _aiStartAddress; public int _aoStartAddress; public string _dataformat; public bool _addressstartwithzero; public bool _stringReverse; private ModbusTcpNet _readerClient = null; private WcfPlc _wcfPlc = null; public bool IsCommunicationError { get; set; } = false; private R_TRIG _trigRetryConnect = new R_TRIG(); private Stopwatch _stopwatchTotal = new Stopwatch(); private bool _enableLog = true; private int _failCount = 0; private object _locker = new object(); protected override void SetParameter(XmlElement nodeParameter) { _address = nodeParameter.GetAttribute("ip"); _port = Convert.ToInt32(nodeParameter.GetAttribute("port")); _station = (byte)Convert.ToInt32(nodeParameter.GetAttribute("station_id")); //_stringReverse = Convert.ToBoolean(nodeParameter.GetAttribute("stringReverse")); _diStartAddress = int.Parse(nodeParameter.GetAttribute("diStartAddress")); _aiStartAddress = int.Parse(nodeParameter.GetAttribute("aiStartAddress")); _doStartAddress = int.Parse(nodeParameter.GetAttribute("doStartAddress")); _aoStartAddress = int.Parse(nodeParameter.GetAttribute("aoStartAddress")); int interval = nodeParameter.HasAttribute("interval") ? int.Parse(nodeParameter.GetAttribute("interval")) : 50; //_dataformat = nodeParameter.GetAttribute("dataformat"); //DisconnectAlarm = SubscribeAlarm($"{Name}.DisconnectAlarm", "", ResetAlarm); //DisconnectAlarm.Id = 1030; //CommunicationErrorAlarm = SubscribeAlarm($"{Name}.DisconnectAlarm", "", ResetAlarm); //CommunicationErrorAlarm.Id = 1031; _thread = new PeriodicJob(interval, OnTimer, Name); _enableLog = SC.GetValue($"System.ModbusCommunicationEnableLogMessage"); OP.Subscribe($"Sysytem.{Name}.ModbusPLC", InvokeReset); if (SC.GetValue("System.IsSimulatorMode")) { _wcfPlc = new WcfPlc("System", Name, $"WcfPlc_{Name}"); _wcfPlc.Initialize(); } else { _readerClient = new ModbusTcpNet(_address, _port, _station); Open(); } } public int _connecteTimes { get; set; } private R_TRIG _trigConnected = new R_TRIG(); private R_TRIG _trigReadDoAndAo = new R_TRIG(); //public override bool ResetAlarm() //{ // Reset(); // return true; //} public override void Initialize(string module, string name, List lstBuffers, IIoBuffer buffer, XmlElement nodeParameter, string ioMappingPathFile, string ioModule) { //if (SC.GetValue("System.IsSimulatorMode")) // _wcfPlc.Initialize(); Module = module; Name = name; _source = module + "." + name; _buffer = buffer; _nodeParameter = nodeParameter; _blockSections = lstBuffers; buffer.SetBufferBlock(_source, lstBuffers); buffer.SetIoMapByModule(_source, 0, ioMappingPathFile, ioModule); SetParameter(nodeParameter); State = IoProviderStateEnum.Uninitialized; } protected override bool OnTimer() { try { _stopwatchTotal.Start(); foreach (var bufferSection in _blockSections) { if (bufferSection.Type == IoType.DI) { bool[] diBuffer = ReadDi(bufferSection.Offset, bufferSection.Size); if (diBuffer != null) { _buffer.SetDiBuffer(_source, bufferSection.Offset, diBuffer); //TraceArray(diBuffer); } } else if (bufferSection.Type == IoType.DO) { if (_trigConnected.Q && !_trigReadDoAndAo.M) { bool[] doBuffer = ReadDo(bufferSection.Offset, bufferSection.Size); if (doBuffer != null) { _buffer.SetDoBuffer(_source, bufferSection.Offset, doBuffer); } } } else if (bufferSection.Type == IoType.AI) { if (bufferSection.AIOType == typeof(float)) { float[] aiBuffer = ReadAiFloat(bufferSection.Offset, bufferSection.Size); if (aiBuffer != null) { _buffer.SetAiBufferFloat(_source, bufferSection.Offset, aiBuffer); } } else { short[] aiBuffer = ReadAi(bufferSection.Offset, bufferSection.Size); if (aiBuffer != null) { _buffer.SetAiBuffer(_source, bufferSection.Offset, aiBuffer); } } } else if (bufferSection.Type == IoType.AO) { if (bufferSection.AIOType == typeof(float)) { if (_trigConnected.Q && !_trigReadDoAndAo.M) { float[] aoBuffer = ReadAoFloat(bufferSection.Offset, bufferSection.Size); if (aoBuffer != null) { _buffer.SetAoBufferFloat(_source, bufferSection.Offset, aoBuffer); } } } else { if (_trigConnected.Q && !_trigReadDoAndAo.M) { short[] aoBuffer = ReadAo(bufferSection.Offset, bufferSection.Size); if (aoBuffer != null) { _buffer.SetAoBuffer(_source, bufferSection.Offset, aoBuffer); } } } } } if (!_trigReadDoAndAo.M) _trigReadDoAndAo.CLK = true; //if (SC.GetValue("System.IsSimulatorMode")) { Dictionary dos = _buffer.GetDoBuffer(_source); if (dos != null) { foreach (var doo in dos) { WriteDo(doo.Key, doo.Value); } } var aoSection = _blockSections.FirstOrDefault(P => P.Type == IoType.AO); if (aoSection != null) { if (aoSection.AIOType == typeof(float)) { Dictionary aos = _buffer.GetAoBufferFloat(_source); if (aos != null) { foreach (var ao in aos) { WriteAoFloat(ao.Key, ao.Value); } } } else { Dictionary aos = _buffer.GetAoBuffer(_source); if (aos != null) { foreach (var ao in aos) { WriteAo(ao.Key, ao.Value); } } } } } var comunicationSpanTotal = (int)_stopwatchTotal.ElapsedMilliseconds; //LOG.Write($"Modbus {comunicationSpanTotal}"); _stopwatchTotal.Restart(); } catch (Exception ex) { LOG.Write(ex); Close(); } return true; } public override void Reset() { _trigError.RST = true; _trigNotConnected.RST = true; if (!_trigConnected.M) { if (!SC.GetValue("System.IsSimulatorMode")) { Close(); Open(); } } } private void TrigDisconnectAlarm() { _trigNotConnected.CLK = true; if (_trigNotConnected.T) { EV.PostInfoLog(Module, $"{Module} {_address}:{_port} connected"); } if (_trigNotConnected.R) { EV.PostAlarmLog(Module, $"{Module} {_address}:{_port} not connected"); } } protected override bool[] ReadDi(int offset, int size) { if (SC.GetValue("System.IsSimulatorMode")) { int address = offset + _aiStartAddress; var ret = _wcfPlc.ReadBool(address.ToString(), out bool[] data, size, out _); return data; } else { if (_trigNotConnected.M) return null; var dataDi = DATA.Poll($"System.{Name}.DIItemList"); bool[] data = new bool[size]; if (dataDi != null) { List item = (List)dataDi; int address = _diStartAddress; int iOldAddress = _diStartAddress; ushort iCount = 0; int iIndex = 0; for (int i = 0; i < item.Count; i++) { int.TryParse(item[i].Address, out int iNewAddress); if (iNewAddress == iOldAddress) { iCount++; continue; } else { if (iNewAddress == iOldAddress + 1) { iCount++; iOldAddress = iNewAddress; } else { OperateResult ret; lock (_locker) { ret = _readerClient.ReadInt16(address.ToString(), iCount); } if (ret != null && ret.IsSuccess) { for (int j = 0; j < ret.Content.Length; j++) { data[iIndex + j] = ret.Content[j] > 0 ? true : false; } _failCount = 0; } else { _failCount++; } iIndex = iNewAddress - _diStartAddress; address = iNewAddress; iOldAddress = iNewAddress; iCount = 1; } } if (i == item.Count - 1) { OperateResult ret; lock (_locker) { ret = _readerClient.ReadInt16(address.ToString(), iCount); } if (ret != null && ret.IsSuccess) { for (int j = 0; j < ret.Content.Length; j++) { data[iIndex + j] = ret.Content[j] > 0 ? true : false; } _failCount = 0; } else { _failCount++; } } } } if (_failCount >= 5) TrigDisconnectAlarm(); return data; } } protected override float[] ReadAiFloat(int offset, int size) { if (SC.GetValue("System.IsSimulatorMode")) { int address = offset + _aiStartAddress; var ret = _wcfPlc.ReadFloat(address.ToString(), out float[] data, size, out _); return data; } else { if (_trigNotConnected.M) return null; var dataAi = DATA.Poll($"System.{Name}.AIItemList"); float[] data = new float[size]; if (dataAi != null) { List item = (List)dataAi; int address = _aiStartAddress; int iOldAddress = _aiStartAddress; ushort iCount = 0; int iIndex = 0; for (int i = 0; i < item.Count; i++) { int.TryParse(item[i].Address, out int iNewAddress); if (iNewAddress == iOldAddress) { iCount++; continue; } else { if (iNewAddress == iOldAddress + 2) { iCount++; iOldAddress = iNewAddress; } else { Task> ret; lock (_locker) { ret = _readerClient.ReadFloatAsync(address.ToString(), iCount); } if (ret != null && ret.Result.IsSuccess) { for (int j = 0; j < ret.Result.Content.Length; j++) { data[iIndex + j * 2] = ret.Result.Content[j]; } } iIndex = iNewAddress - _aiStartAddress; address = iNewAddress; iOldAddress = iNewAddress; iCount = 1; } } if (i == item.Count - 1) { Task> ret; lock (_locker) { ret = _readerClient.ReadFloatAsync(address.ToString(), iCount); } if (ret != null && ret.Result.IsSuccess) { for (int j = 0; j < ret.Result.Content.Length; j++) { data[iIndex + j * 2] = ret.Result.Content[j]; } } } } } return data; } } protected bool[] ReadDo(int offset, int size) { if (SC.GetValue("System.IsSimulatorMode")) { return null; } else { var dataDo = DATA.Poll($"System.{Name}.DOItemList"); bool[] data = new bool[size]; if (dataDo != null) { List item = (List)dataDo; int address = _doStartAddress; int iOldAddress = _doStartAddress; ushort iCount = 0; int iIndex = 0; for (int i = 0; i < item.Count; i++) { int.TryParse(item[i].Address, out int iNewAddress); if (iNewAddress == iOldAddress) { iCount++; continue; } else { if (iNewAddress == iOldAddress + 1) { iCount++; iOldAddress = iNewAddress; } else { var ret = _readerClient.ReadInt16(address.ToString(), iCount); if (ret != null && ret.IsSuccess) { for (int j = 0; j < ret.Content.Length; j++) { data[iIndex + j] = ret.Content[j] > 0 ? true : false; } } iIndex = iNewAddress - _doStartAddress; address = iNewAddress; iOldAddress = iNewAddress; iCount = 1; } } if (i == item.Count - 1) { var ret = _readerClient.ReadInt16(address.ToString(), iCount); if (ret != null && ret.IsSuccess) { for (int j = 0; j < ret.Content.Length; j++) { data[iIndex + j] = ret.Content[j] > 0 ? true : false; } } } } } return data; } } protected override short[] ReadAi(int offset, int size) { if (SC.GetValue("System.IsSimulatorMode")) { int address = offset + _aiStartAddress; var ret = _wcfPlc.ReadInt16(address.ToString(), out short[] data, size, out _); return data; } else { if (_trigNotConnected.M) return null; var dataAi = DATA.Poll($"System.{Name}.AIItemList"); short[] data = new short[size]; if (dataAi != null) { List item = (List)dataAi; int address = _aiStartAddress; int iOldAddress = _aiStartAddress; ushort iCount = 0; int iIndex = 0; for (int i = 0; i < item.Count; i++) { int.TryParse(item[i].Address, out int iNewAddress); if (iNewAddress == iOldAddress) { iCount++; continue; } else { if (iNewAddress == iOldAddress + 1) { iCount++; iOldAddress = iNewAddress; } else { OperateResult ret; lock (_locker) { ret = _readerClient.ReadInt16(address.ToString(), iCount); } if (ret != null && ret.IsSuccess) { for (int j = 0; j < ret.Content.Length; j++) { data[iIndex + j] = ret.Content[j]; } } iIndex = iNewAddress - _aiStartAddress; address = iNewAddress; iOldAddress = iNewAddress; iCount = 1; } } if (i == item.Count - 1) { OperateResult ret; lock (_locker) { ret = _readerClient.ReadInt16(address.ToString(), iCount); } if (ret != null && ret.IsSuccess) { for (int j = 0; j < ret.Content.Length; j++) { data[iIndex + j] = ret.Content[j]; } } } } } return data; } } protected float[] ReadAoFloat(int offset, int size) { if (SC.GetValue("System.IsSimulatorMode")) { return null; } else { var dataAo = DATA.Poll($"System.{Name}.AOItemList"); float[] data = new float[size]; if (dataAo != null) { List item = (List)dataAo; int address = _aoStartAddress; int iOldAddress = _aoStartAddress; ushort iCount = 0; int iIndex = 0; for (int i = 0; i < item.Count; i++) { int.TryParse(item[i].Address, out int iNewAddress); if (iNewAddress == iOldAddress) { iCount++; continue; } else { if (iNewAddress == iOldAddress + 2) { iCount++; iOldAddress = iNewAddress; } else { OperateResult ret; lock (_locker) { ret = _readerClient.ReadFloat(address.ToString(), iCount); } if (ret != null && ret.IsSuccess) { for (int j = 0; j < ret.Content.Length; j++) { data[iIndex + j * 2] = ret.Content[j]; } } iIndex = iNewAddress - _aoStartAddress; address = iNewAddress; iOldAddress = iNewAddress; iCount = 1; } } if (i == item.Count - 1) { OperateResult ret; lock (_locker) { ret = _readerClient.ReadFloat(address.ToString(), iCount); } if (ret != null && ret.IsSuccess) { for (int j = 0; j < ret.Content.Length; j++) { data[iIndex + j * 2] = ret.Content[j]; } } } } } return data; } } protected short[] ReadAo(int offset, int size) { if (SC.GetValue("System.IsSimulatorMode")) { return null; } else { var dataAo = DATA.Poll($"System.{Name}.AOItemList"); short[] data = new short[size]; if (dataAo != null) { List item = (List)dataAo; int address = _aoStartAddress; int iOldAddress = _aoStartAddress; ushort iCount = 0; int iIndex = 0; for (int i = 0; i < item.Count; i++) { int.TryParse(item[i].Address, out int iNewAddress); if (iNewAddress == iOldAddress) { iCount++; continue; } else { if (iNewAddress == iOldAddress + 1) { iCount++; iOldAddress = iNewAddress; } else { OperateResult ret; lock (_locker) { ret = _readerClient.ReadInt16(address.ToString(), iCount); } if (ret != null && ret.IsSuccess) { for (int j = 0; j < ret.Content.Length; j++) { data[iIndex + j] = ret.Content[j]; } } iIndex = iNewAddress - _aoStartAddress; address = iNewAddress; iOldAddress = iNewAddress; iCount = 1; } } if (i == item.Count - 1) { OperateResult ret; lock (_locker) { ret = _readerClient.ReadInt16(address.ToString(), iCount); } if (ret != null && ret.IsSuccess) { for (int j = 0; j < ret.Content.Length; j++) { data[iIndex + j] = ret.Content[j]; } } } } } return data; } } public override bool SetValueFloat(AOAccessor aoItem, float value) { if (SC.GetValue("System.IsSimulatorMode")) return true; if (!_trigConnected.M) return false; if (_trigNotConnected.M) return false; try { int address = aoItem.Index + _aoStartAddress; OperateResult ret; lock (_locker) { ret = _readerClient.Write(address.ToString(), new float[] { value }); } if (ret != null) { return ret.IsSuccess; } else { return false; } } catch (Exception) { _trigConnected.CLK = false; return false; } } public override bool SetValue(DOAccessor doItem, bool value) { if (SC.GetValue("System.IsSimulatorMode")) return true; if (!_trigConnected.M) return false; if (_trigNotConnected.M) return false; try { int address = doItem.Index + _doStartAddress; var ret2 = _readerClient.Write(address.ToString(), (short)(value ? 1 : 0)); return ret2.IsSuccess; } catch (Exception) { _trigConnected.CLK = false; return false; } } protected override void Close() { try { _readerClient.ConnectClose(); _readerClient.Dispose(); _trigConnected.RST = true; } catch (Exception ex) { LOG.Write(ex.Message); } } protected override void Open() { _readerClient.IpAddress = _address; _readerClient.Port = _port; _readerClient?.ConnectClose(); try { var ret = _readerClient.ConnectServer(); if (ret.IsSuccess) _trigConnected.CLK = true; else { //DisconnectAlarm.Description = ret.Message; //DisconnectAlarm.Set(); LOG.Write(ret.Message); } } catch (Exception ex) { IsCommunicationError = true; LOG.Write(ex.Message); //CommunicationErrorAlarm.Description = ex.Message; //CommunicationErrorAlarm.Set(); } } public byte[] ReadResultRender(OperateResult result, string address) { byte[] buffer = new byte[32]; if (result.IsSuccess) { _connecteTimes = 0; IsCommunicationError = false; var dat2 = (Convert.ToUInt32(result.Content.ToString()) & 0xFFFF); var dat1 = (Convert.ToUInt32(result.Content.ToString()) >> 16 & 0xFFFF); uint[] data = new uint[] { dat1, dat2 }; for (int j = 0; j < 2; j++) { for (int i = 0; i < 16; i++) { buffer[j * 16 + i] = Convert.ToByte((data[j] >> i) & 0x01); } } string str = string.Join("", Array.ConvertAll(buffer, x => x.ToString())); if (_enableLog) LOG.Info($"Read Success,Data:{ str} ({ result.Content.ToString()}:{dat1}、{dat2})"); return buffer; } else { IsCommunicationError = true; EV.PostAlarmLog("System.PLC", $"[{address}] Read Failed {Environment.NewLine}Reason:{result.ToMessageShowString()}"); } return buffer; } public void WriteResultRender(OperateResult result, string address, int data, string str) { if (result.IsSuccess) { _connecteTimes = 0; IsCommunicationError = false; if (_enableLog) LOG.Info("Write Success,Data" + str + "(" + data.ToString() + ")"); } else { IsCommunicationError = true; EV.PostAlarmLog("System.PLC", $"[{address}] Write Failed {Environment.NewLine}Reason:{result.ToMessageShowString()}"); } } public bool InvokeReset(string arg1, object[] arg2) { _connecteTimes = 0; IsCommunicationError = false; _trigRetryConnect.RST = true; return true; } protected override void WriteDo(int offset, bool[] buffer) { if (_readerClient != null) { return; int address = offset + _doStartAddress; List temp = new List(); for (int i = 0; i < buffer.Length; i++) { temp.Add((short)(buffer[i] ? 1 : 0)); } lock (_locker) { var ret = _readerClient.Write(address.ToString(), temp.ToArray()); } } else { int address = offset + _doStartAddress; _wcfPlc.WriteBool(address.ToString(), buffer, out string reason); } } protected override void WriteAo(int offset, short[] buffer) { if (_readerClient != null) { int address = offset + _aoStartAddress; int size = 1; short[] temp; int i = 0; for (; i < buffer.Length / size; i++) { temp = new short[size]; Array.Copy(buffer, i * size, temp, 0, size); OperateResult ret; lock (_locker) { ret = _readerClient.Write((address + i * size).ToString(), temp); } if (ret != null && !ret.IsSuccess) { return; } } if (buffer.Length - i * size > 0) { temp = new short[buffer.Length - i * size]; Array.Copy(buffer, i * size, temp, 0, buffer.Length - i * size); OperateResult ret; lock (_locker) { ret = _readerClient.Write((address + i * size).ToString(), temp); } if (ret != null && !ret.IsSuccess) { return; } } } else { int address = offset + _aoStartAddress; _wcfPlc?.WriteInt16(address.ToString(), buffer, out _); } } protected override void WriteAoFloat(int offset, float[] data) { if (_readerClient != null) { return; int address = offset + _aoStartAddress; int size = 2; float[] temp; int i = 0; for (; i < data.Length / size; i++) { temp = new float[size]; Array.Copy(data, i * size, temp, 0, size); OperateResult ret; lock (_locker) { ret = _readerClient.Write((address + i * size).ToString(), temp); } if (ret != null && !ret.IsSuccess) { return; } } if (data.Length - i * size > 0) { temp = new float[data.Length - i * size]; Array.Copy(data, i * size, temp, 0, data.Length - i * size); OperateResult ret; lock (_locker) { ret = _readerClient.Write((address + i * size).ToString(), temp); } if (ret != null && !ret.IsSuccess) { return; } } } else { int address = offset + _aoStartAddress; _wcfPlc?.WriteFloat(address.ToString(), data, out _); } } } }