using Common.Attributes;
using NModbus;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using static Common.Attributes.ATSCommandAttribute;
namespace DeviceCommand.Base
{
///
/// ModbusTcp协议
///
[ATSCommand]
[DeviceCategory("全部驱动")] // 添加分类属性
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; }
///
/// 创建ModbusTCP设备对象
///
/// IP地址
/// 端口号
/// 发送超时时间
/// 接收超时时间
public ModbusTcp CreateDevice(string ipAddress, int port, int sendTimeout = 3000, int receiveTimeout = 3000)
{
IPAddress = ipAddress;
Port = port;
SendTimeout = sendTimeout;
ReceiveTimeout = receiveTimeout;
return this;
}
///
/// 修改ModbusTCP连接参数
///
///
/// IP地址
/// 端口号
/// 发送超时时间
/// 接收超时时间
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 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!;
// 比较IP地址和端口
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;
}
///
/// 设备初始化
///
/// ModbusTcp实例
public static void ModbusTcpInitialize(ModbusTcp modbusTcp)
{
try
{
if (modbusTcp.TcpClient.Connected)
{
Console.WriteLine("设备已初始化,无需重复初始化");
return;
}
modbusTcp.TcpClient = new TcpClient();
modbusTcp.TcpClient.SendTimeout = modbusTcp.SendTimeout;
modbusTcp.TcpClient.ReceiveTimeout = modbusTcp.ReceiveTimeout;
Console.WriteLine($"ModbusTCP设备初始化完成");
}
catch (Exception ex)
{
Console.WriteLine($"设备初始化失败: {ex.Message}");
throw;
}
}
///
/// 断开
///
/// ModbusTcp实例
public static void Close(ModbusTcp modbusTcp)
{
try
{
if (modbusTcp.TcpClient.Connected)
{
modbusTcp.TcpClient.Close();
Console.WriteLine("ModbusTCP连接已断开");
}
}
catch (Exception ex)
{
Console.WriteLine($"断开连接失败: {ex.Message}");
throw;
}
}
///
/// 读保存寄存器
///
///
/// 设备地址
/// 起始地址
/// 读取数量
///
///
///
public static async Task 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通讯异常:读取操作在 {modbusTcp.ReceiveTimeout} ms内未完成");
}
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通讯异常:写入操作在 {modbusTcp.ReceiveTimeout} ms内未完成");
}
}
///
/// 写入多个寄存器
///
///
/// 从设备地址
/// 起始寄存器地址
/// 值列表
///
///
///
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通讯异常:写入操作在 {modbusTcp.ReceiveTimeout} ms内未完成");
}
}
///
/// 读取线圈
///
/// ModbusTcp实例
/// 从机地址
/// 起始地址
/// 读取数量
/// 支持中途取消发送指令
/// 布尔数组
public static async Task ReadCoilAsync(ModbusTcp modbusTcp, byte slaveAddress, ushort startAddress, ushort numberOfPoints, CancellationToken ct = default)
{
try
{
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读取线圈操作在 {modbusTcp.ReceiveTimeout} ms内未完成");
}
return await readTask;
}
catch (Exception ex)
{
Console.WriteLine($"读取线圈失败: {ex.Message}");
throw;
}
}
///
/// 写入单个线圈
///
///
/// 从设备地址
/// 线圈地址
/// 值
///
///
///
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通讯异常:写入操作在 {modbusTcp.ReceiveTimeout} ms内未完成");
}
}
///
/// 写入多个线圈
///
///
/// 从设备地址
/// 起始线圈地址
/// 值列表
///
///
///
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通讯异常:写入操作在 {modbusTcp.ReceiveTimeout} ms内未完成");
}
}
///
/// 紧急停止
///
/// ModbusTcp实例
public static void ModbusTcpStopNow(ModbusTcp modbusTcp)
{
try
{
if (modbusTcp.TcpClient.Connected)
{
modbusTcp.TcpClient.Close();
Console.WriteLine("紧急停止:ModbusTCP连接已断开");
}
}
catch (Exception ex)
{
Console.WriteLine($"紧急停止失败: {ex.Message}");
}
}
///
/// 读取输入寄存器
///
/// ModbusTcp实例
/// 从机地址
/// 起始地址
/// 读取数量
/// 支持中途取消发送指令
/// ushort数组
public static async Task ReadInputRegisterAsync(ModbusTcp modbusTcp, byte slaveAddress, ushort startAddress, ushort numberOfPoints, CancellationToken ct = default)
{
try
{
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读取输入寄存器操作在 {modbusTcp.ReceiveTimeout} ms内未完成");
}
return await readTask;
}
catch (Exception ex)
{
Console.WriteLine($"读取输入寄存器失败: {ex.Message}");
throw;
}
}
}
}