using NModbus; using System; using System.IO.Ports; using System.Net; using System.Net.Sockets; using System.Threading; using System.Threading.Tasks; namespace DeviceCommand.Base { public class ModbusTcp : IModbusDevice { public string IPAddress { get; private set; } = "127.0.0.1"; public int Port { get; private set; } = 502; public int SendTimeout { get; private set; } = 3000; public int ReceiveTimeout { get; private set; } = 3000; public SerialPort SerialPort { get; set; } public TcpClient TcpClient { get; set; } = new TcpClient(); public IModbusMaster Modbus { get; set; } protected readonly SemaphoreSlim _commLock = new(1, 1); public void ConfigureDevice(string ipAddress, int port, int sendTimeout = 3000, int receiveTimeout = 3000) { IPAddress = ipAddress; Port = port; SendTimeout = sendTimeout; ReceiveTimeout = receiveTimeout; } public virtual async Task ConnectAsync(CancellationToken ct = default) { await _commLock.WaitAsync(ct); try { if (TcpClient.Connected) { var remoteEndPoint = (IPEndPoint)TcpClient.Client.RemoteEndPoint!; if (remoteEndPoint.Address.MapToIPv4().ToString() == IPAddress && remoteEndPoint.Port == Port) return true; TcpClient.Close(); TcpClient.Dispose(); TcpClient = new TcpClient(); } await TcpClient.ConnectAsync(IPAddress, Port, ct); Modbus = new ModbusFactory().CreateMaster(TcpClient); return true; } finally { _commLock.Release(); } } public virtual void Close() { if (TcpClient.Connected) TcpClient.Close(); } public async Task WriteSingleRegisterAsync(byte slaveAddress, ushort registerAddress, ushort value, CancellationToken ct = default) { await _commLock.WaitAsync(ct); try { await Modbus.WriteSingleRegisterAsync(slaveAddress, registerAddress, value).WaitAsync(TimeSpan.FromMinutes(SendTimeout),ct); } finally { _commLock.Release(); } } public async Task WriteMultipleRegistersAsync(byte slaveAddress, ushort startAddress, ushort[] values, CancellationToken ct = default) { await _commLock.WaitAsync(ct); try { await Modbus.WriteMultipleRegistersAsync(slaveAddress, startAddress, values).WaitAsync(TimeSpan.FromMinutes(SendTimeout), ct); } finally { _commLock.Release(); } } public async Task ReadHoldingRegistersAsync(byte slaveAddress, ushort startAddress, ushort numberOfPoints, CancellationToken ct = default) { await _commLock.WaitAsync(ct); try { var result =await Modbus.ReadHoldingRegistersAsync(slaveAddress, startAddress, numberOfPoints).WaitAsync(TimeSpan.FromMinutes(SendTimeout), ct); return result; } finally { _commLock.Release(); } } public async Task WriteSingleCoilAsync(byte slaveAddress, ushort coilAddress, bool value, CancellationToken ct = default) { await _commLock.WaitAsync(ct); try { await Modbus.WriteSingleCoilAsync(slaveAddress, coilAddress, value).WaitAsync(TimeSpan.FromMinutes(SendTimeout), ct); } finally { _commLock.Release(); } } public async Task ReadCoilsAsync(byte slaveAddress, ushort startAddress, ushort numberOfPoints, CancellationToken ct = default) { await _commLock.WaitAsync(ct); try { var result = await Modbus.ReadCoilsAsync(slaveAddress, startAddress, numberOfPoints).WaitAsync(TimeSpan.FromMinutes(SendTimeout), ct); return result; } finally { _commLock.Release(); } } public async Task ReadInputRegistersAsync(byte slaveAddress, ushort startAddress, ushort numberOfPoints, CancellationToken ct = default) { await _commLock.WaitAsync(ct); try { var result = await Modbus.ReadInputRegistersAsync(slaveAddress, startAddress, numberOfPoints).WaitAsync(TimeSpan.FromMinutes(SendTimeout), ct); return result; } finally { _commLock.Release(); } } } }