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; } } } }