147 lines
7.2 KiB
C#
147 lines
7.2 KiB
C#
using NModbus;
|
|
using System;
|
|
using System.Net;
|
|
using System.Net.Sockets;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
|
|
namespace DeviceCommand.Base
|
|
{
|
|
public class ModbusTcp
|
|
{
|
|
public string IPAddress { get; set; } = "127.0.0.1";
|
|
public int Port { get; set; } = 502;
|
|
public int SendTimeout { get; set; } = 3000;
|
|
public int ReceiveTimeout { get; set; } = 3000;
|
|
public TcpClient TcpClient { get; set; } = new();
|
|
public IModbusMaster Modbus { get; set; }
|
|
|
|
public ModbusTcp CreateDevice(string ipAddress, int port, int sendTimeout = 3000, int receiveTimeout = 3000)
|
|
{
|
|
IPAddress = ipAddress;
|
|
Port = port;
|
|
SendTimeout = sendTimeout;
|
|
ReceiveTimeout = receiveTimeout;
|
|
return this;
|
|
}
|
|
|
|
public static void ChangeDeviceConfig(ModbusTcp modbusTcp, string ipAddress, int port, int sendTimeout = 3000, int receiveTimeout = 3000)
|
|
{
|
|
modbusTcp.IPAddress = ipAddress;
|
|
modbusTcp.Port = port;
|
|
if (sendTimeout > 0) modbusTcp.SendTimeout = sendTimeout;
|
|
if (receiveTimeout > 0) modbusTcp.ReceiveTimeout = receiveTimeout;
|
|
}
|
|
|
|
public static async Task<bool> ConnectAsync(ModbusTcp modbusTcp, CancellationToken ct = default)
|
|
{
|
|
if (!modbusTcp.TcpClient.Connected)
|
|
{
|
|
modbusTcp.TcpClient.Close();
|
|
modbusTcp.TcpClient.Dispose();
|
|
modbusTcp.TcpClient = new TcpClient();
|
|
await modbusTcp.TcpClient.ConnectAsync(modbusTcp.IPAddress, modbusTcp.Port, ct);
|
|
modbusTcp.Modbus = new ModbusFactory().CreateMaster(modbusTcp.TcpClient);
|
|
}
|
|
else
|
|
{
|
|
var remoteEndPoint = (IPEndPoint)modbusTcp.TcpClient.Client.RemoteEndPoint!;
|
|
var ip = remoteEndPoint.Address.MapToIPv4().ToString();
|
|
bool isSameAddress = ip.Equals(modbusTcp.IPAddress);
|
|
bool isSamePort = remoteEndPoint.Port == modbusTcp.Port;
|
|
if (!isSameAddress || !isSamePort)
|
|
{
|
|
modbusTcp.TcpClient.Close();
|
|
modbusTcp.TcpClient.Dispose();
|
|
modbusTcp.TcpClient = new TcpClient();
|
|
await modbusTcp.TcpClient.ConnectAsync(modbusTcp.IPAddress, modbusTcp.Port, ct);
|
|
modbusTcp.Modbus = new ModbusFactory().CreateMaster(modbusTcp.TcpClient);
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
public static void ModbusTcpInitialize(ModbusTcp modbusTcp)
|
|
{
|
|
if (!modbusTcp.TcpClient.Connected)
|
|
{
|
|
modbusTcp.TcpClient = new TcpClient();
|
|
modbusTcp.TcpClient.SendTimeout = modbusTcp.SendTimeout;
|
|
modbusTcp.TcpClient.ReceiveTimeout = modbusTcp.ReceiveTimeout;
|
|
}
|
|
}
|
|
|
|
public static void Close(ModbusTcp modbusTcp)
|
|
{
|
|
if (modbusTcp.TcpClient.Connected)
|
|
{
|
|
modbusTcp.TcpClient.Close();
|
|
}
|
|
}
|
|
|
|
public static async Task<ushort[]> ReadHoldingRegistersAsync(ModbusTcp modbusTcp, byte slaveAddress, ushort startAddress, ushort numberOfPoints, CancellationToken ct = default)
|
|
{
|
|
var readTask = modbusTcp.Modbus.ReadHoldingRegistersAsync(slaveAddress, startAddress, numberOfPoints).WaitAsync(ct);
|
|
var timeoutTask = Task.Delay(modbusTcp.ReceiveTimeout, ct);
|
|
var completedTask = await Task.WhenAny(readTask, timeoutTask);
|
|
if (completedTask == timeoutTask) throw new TimeoutException($"ModbusTCP读取保持寄存器超时");
|
|
return await readTask;
|
|
}
|
|
|
|
public static async Task WriteSingleRegisterAsync(ModbusTcp modbusTcp, byte slaveAddress, ushort registerAddress, ushort value, CancellationToken ct = default)
|
|
{
|
|
var sendTask = modbusTcp.Modbus.WriteSingleRegisterAsync(slaveAddress, registerAddress, value).WaitAsync(ct);
|
|
var timeoutTask = Task.Delay(modbusTcp.ReceiveTimeout, ct);
|
|
var completedTask = await Task.WhenAny(sendTask, timeoutTask);
|
|
if (completedTask == timeoutTask) throw new TimeoutException($"ModbusTCP写单寄存器超时");
|
|
}
|
|
|
|
public static async Task WriteMultipleRegistersAsync(ModbusTcp modbusTcp, byte slaveAddress, ushort startAddress, ushort[] values, CancellationToken ct = default)
|
|
{
|
|
var sendTask = modbusTcp.Modbus.WriteMultipleRegistersAsync(slaveAddress, startAddress, values).WaitAsync(ct);
|
|
var timeoutTask = Task.Delay(modbusTcp.ReceiveTimeout, ct);
|
|
var completedTask = await Task.WhenAny(sendTask, timeoutTask);
|
|
if (completedTask == timeoutTask) throw new TimeoutException($"ModbusTCP写多寄存器超时");
|
|
}
|
|
|
|
public static async Task<bool[]> ReadCoilAsync(ModbusTcp modbusTcp, byte slaveAddress, ushort startAddress, ushort numberOfPoints, CancellationToken ct = default)
|
|
{
|
|
var readTask = modbusTcp.Modbus.ReadCoilsAsync(slaveAddress, startAddress, numberOfPoints).WaitAsync(ct);
|
|
var timeoutTask = Task.Delay(modbusTcp.ReceiveTimeout, ct);
|
|
var completedTask = await Task.WhenAny(readTask, timeoutTask);
|
|
if (completedTask == timeoutTask) throw new TimeoutException($"ModbusTCP读取线圈超时");
|
|
return await readTask;
|
|
}
|
|
|
|
public static async Task WriteSingleCoilAsync(ModbusTcp modbusTcp, byte slaveAddress, ushort coilAddress, bool value, CancellationToken ct = default)
|
|
{
|
|
var sendTask = modbusTcp.Modbus.WriteSingleCoilAsync(slaveAddress, coilAddress, value).WaitAsync(ct);
|
|
var timeoutTask = Task.Delay(modbusTcp.ReceiveTimeout, ct);
|
|
var completedTask = await Task.WhenAny(sendTask, timeoutTask);
|
|
if (completedTask == timeoutTask) throw new TimeoutException($"ModbusTCP写单线圈超时");
|
|
}
|
|
|
|
public static async Task WriteMultipleCoilsAsync(ModbusTcp modbusTcp, byte slaveAddress, ushort startAddress, bool[] values, CancellationToken ct = default)
|
|
{
|
|
var sendTask = modbusTcp.Modbus.WriteMultipleCoilsAsync(slaveAddress, startAddress, values).WaitAsync(ct);
|
|
var timeoutTask = Task.Delay(modbusTcp.ReceiveTimeout, ct);
|
|
var completedTask = await Task.WhenAny(sendTask, timeoutTask);
|
|
if (completedTask == timeoutTask) throw new TimeoutException($"ModbusTCP写多线圈超时");
|
|
}
|
|
|
|
public static void ModbusTcpStopNow(ModbusTcp modbusTcp)
|
|
{
|
|
if (modbusTcp.TcpClient.Connected) modbusTcp.TcpClient.Close();
|
|
}
|
|
|
|
public static async Task<ushort[]> ReadInputRegisterAsync(ModbusTcp modbusTcp, byte slaveAddress, ushort startAddress, ushort numberOfPoints, CancellationToken ct = default)
|
|
{
|
|
var readTask = modbusTcp.Modbus.ReadInputRegistersAsync(slaveAddress, startAddress, numberOfPoints).WaitAsync(ct);
|
|
var timeoutTask = Task.Delay(modbusTcp.ReceiveTimeout, ct);
|
|
var completedTask = await Task.WhenAny(readTask, timeoutTask);
|
|
if (completedTask == timeoutTask) throw new TimeoutException($"ModbusTCP读取输入寄存器超时");
|
|
return await readTask;
|
|
}
|
|
}
|
|
}
|