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<int> 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<int>(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());
|
}
|
}
|
}
|
|
/// <summary>
|
/// 写单独地址
|
/// </summary>
|
/// <param name="address">10进制表示的地址,首位表示类型 例如 45000</param>
|
/// <param name="writeValue"></param>
|
/// <param name="waitForReply"></param>
|
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<int>() { 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<int> GetMonitorValues(int startAddress, int length)
|
{
|
InitialScanClient();
|
|
ModbusFrame_Send_TCP frame = new ModbusFrame_Send_TCP(ModbusOrder.Read_HoldingRegister, startAddress, length, new List<int>(), 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<int>();
|
}
|
}
|
#endregion
|
}
|
}
|