using Bro.Common.Base; using Bro.Common.Helper; using Bro.Common.Model; using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Net; using System.Net.Sockets; using System.Threading; using System.Threading.Tasks; namespace SchneiderPLC_ModbusTcp { [Device("SchneiderPLC", "施耐德PLC", EnumHelper.DeviceAttributeType.Device)] public class SchneiderPLC_ModbusTcp_Driver : PLCBase { #region PLCBase public override List Read(int startAddress, int length) { PLCItem item = new PLCItem(); item.Address = startAddress.ToString(); item.ItemLength = length; ReadItem(item); return item.ItemValues; } public override void ReadItem(PLCItem item) { item.PLCOpType = EnumHelper.PLCOpType.Read; item.ItemValues.Clear(); InitialOpClient(); ModbusFrame_Send_TCP frame = new ModbusFrame_Send_TCP(item, IConfig.PLCUnitNum); byte[] buffer = new byte[2048]; int length = 0; lock (opClientLock) { opClientHandle.WaitOne(); opClientHandle.Reset(); } opStream.Write(frame.Frame, 0, frame.Frame.Length); length = opStream.Read(buffer, 0, buffer.Length); opClientHandle.Set(); if (length > 0) { ModbusFrame_Receive_TCP receiveFrame = new ModbusFrame_Receive_TCP(buffer.Take(length).ToArray()); item.ItemValues = new List(receiveFrame.BodyFrame.OpValue); } else { //todo empty return } } public override void WriteItem(PLCItem item, bool waitForReply = true) { item.PLCOpType = EnumHelper.PLCOpType.Write; if (item.ItemValues.Count == 0) { throw new ProcessException($"{Name}写入值不能为空"); } InitialOpClient(); int repeatTime = 10; Stopwatch sw = new Stopwatch(); ModbusFrame_Send_TCP frame = new ModbusFrame_Send_TCP(item, IConfig.PLCUnitNum); LogAsync(DateTime.Now, "WriteItem", item.GetDisplayText()); do { try { //LogAsync(DateTime.Now, "Send", frame.GetFrameString()); lock (opClientLock) { opClientHandle.WaitOne(); opClientHandle.Reset(); } opStream.Write(frame.Frame, 0, frame.Frame.Length); if (waitForReply) { ReceiveWriteResult(); } else { Task.Run(() => { ReceiveWriteResult(); }); } repeatTime = 0; } catch (Exception ex) { if (repeatTime > 0) { repeatTime--; opClient.Close(); opClient = null; InitialOpClient(); } else { LogAsync(DateTime.Now, "Send Exception", ex.GetExceptionMessage()); } } } while (repeatTime > 0); } private void ReceiveWriteResult() { try { byte[] buffer = new byte[1024]; int bufferCount = opStream.Read(buffer, 0, buffer.Length); opClientHandle.Set(); if (bufferCount > 0) { ModbusFrame_Receive_TCP receiveFrame = new ModbusFrame_Receive_TCP(buffer.Take(bufferCount).ToArray()); //LogAsync(DateTime.Now, "Rec", receiveFrame.GetFrameString()); } else { //todo empty return } } catch (Exception ex) { if (CurrentState == EnumHelper.DeviceState.DSOpen) { LogAsync(DateTime.Now, "Rec Exception", ex.GetExceptionMessage()); } } } /// /// 写单独地址 /// /// 10进制表示的地址,首位表示类型 例如 45000 /// /// public override void WriteSingleAddress(int address, int writeValue, bool waitForReply = true) { PLCItem item = new PLCItem(); item.Address = address.ToString(); item.ItemLength = 1; item.ItemValues = new List() { writeValue }; WriteItem(item, waitForReply); } #endregion #region DeviceBase protected override void Init() { plcEP = new IPEndPoint(IPAddress.Parse(IConfig.PLCIpAddress), IConfig.PLCPort); } protected override void Start() { InitialOpClient(); InitialScanClient(); base.Start(); } protected override void Stop() { try { scanStream.Close(); scanStream?.Dispose(); scanClient.Close(); opStream.Close(); opStream?.Dispose(); opClient.Close(); scanClient = null; opClient = null; } catch (Exception ex) { LogAsync(DateTime.Now, $"{Name}关闭异常", ex.GetExceptionMessage()); } } #endregion public SchneiderInitialConfig IConfig { get { return InitialConfig as SchneiderInitialConfig; } } static readonly object opClientLock = new object(); readonly ManualResetEvent opClientHandle = new ManualResetEvent(true); TcpClient scanClient = new TcpClient(); NetworkStream scanStream = null; TcpClient opClient = new TcpClient(); NetworkStream opStream = null; IPEndPoint plcEP; private void InitialScanClient() { InitialTcpClient(ref scanClient, ref scanStream); } private void InitialOpClient() { InitialTcpClient(ref opClient, ref opStream); } private void InitialTcpClient(ref TcpClient client, ref NetworkStream stream) { if (client == null || !client.Connected || !client.Client.Connected) { client = new TcpClient(); client.NoDelay = true; client.Client.Blocking = true; client.Connect(plcEP); stream = client.GetStream(); } } #region IMonitor readonly byte[] scanBuffer = new byte[2048]; public override List GetMonitorValues(int startAddress, int length) { InitialScanClient(); ModbusFrame_Send_TCP frame = new ModbusFrame_Send_TCP(ModbusOrder.Read_HoldingRegister, startAddress, length, new List(), 1, IConfig.PLCUnitNum); scanStream.Write(frame.Frame, 0, frame.Frame.Length); int readSize = scanStream.Read(scanBuffer, 0, scanBuffer.Length); if (readSize > 0) { ModbusFrame_Receive_TCP receiveFrame = new ModbusFrame_Receive_TCP(scanBuffer.Take(readSize).ToArray()); return receiveFrame.BodyFrame.OpValue; } else { return new List(); } } #endregion } }