using Common.Attributes; using NModbus; using System; using System.Net.Sockets; using System.Text; using System.Threading; using System.Threading.Tasks; namespace DeviceCommand.Flexible { [ADPCommand] public static class FModbusTCP { private static readonly SemaphoreSlim _commLock = new(1, 1); private static async Task ConnectAsync(string ipAddress, int port, int sendTimeout, int receiveTimeout, CancellationToken ct) { var tcpClient = new TcpClient(); using var cts = CancellationTokenSource.CreateLinkedTokenSource(ct); if (sendTimeout > 0) cts.CancelAfter(sendTimeout); await tcpClient.ConnectAsync(ipAddress, port, cts.Token); return new ModbusFactory().CreateMaster(tcpClient); } #region Holding Registers public static async Task ReadHoldingRegistersAsync( string ipAddress, int port, byte slaveAddress, ushort startAddress, ushort numberOfPoints, int sendTimeout = 3000, int receiveTimeout = 3000, CancellationToken ct = default) { await _commLock.WaitAsync(ct); try { using var master = await ConnectAsync(ipAddress, port, sendTimeout, receiveTimeout, ct) as IDisposable; var result = await ((IModbusMaster)master) .ReadHoldingRegistersAsync(slaveAddress, startAddress, numberOfPoints) .WaitAsync(TimeSpan.FromMilliseconds(receiveTimeout), ct); return result; } finally { _commLock.Release(); } } public static async Task WriteSingleRegisterAsync( string ipAddress, int port, byte slaveAddress, ushort registerAddress, ushort value, int sendTimeout = 3000, int receiveTimeout = 3000, CancellationToken ct = default) { await _commLock.WaitAsync(ct); try { using var master = await ConnectAsync(ipAddress, port, sendTimeout, receiveTimeout, ct) as IDisposable; await ((IModbusMaster)master) .WriteSingleRegisterAsync(slaveAddress, registerAddress, value) .WaitAsync(TimeSpan.FromMilliseconds(sendTimeout),ct); } finally { _commLock.Release(); } } #endregion #region Coils public static async Task ReadCoilsAsync( string ipAddress, int port, byte slaveAddress, ushort startAddress, ushort numberOfPoints, int sendTimeout = 3000, int receiveTimeout = 3000, CancellationToken ct = default) { await _commLock.WaitAsync(ct); try { using var master = await ConnectAsync(ipAddress, port, sendTimeout, receiveTimeout, ct) as IDisposable; var result = await ((IModbusMaster)master) .ReadCoilsAsync(slaveAddress, startAddress, numberOfPoints) .WaitAsync(TimeSpan.FromMilliseconds(receiveTimeout), ct); return result; } finally { _commLock.Release(); } } public static async Task WriteSingleCoilAsync( string ipAddress, int port, byte slaveAddress, ushort coilAddress, bool value, int sendTimeout = 3000, int receiveTimeout = 3000, CancellationToken ct = default) { await _commLock.WaitAsync(ct); try { using var master = await ConnectAsync(ipAddress, port, sendTimeout, receiveTimeout, ct) as IDisposable; await ((IModbusMaster)master) .WriteSingleCoilAsync(slaveAddress, coilAddress, value) .WaitAsync(TimeSpan.FromMilliseconds(sendTimeout),ct); } finally { _commLock.Release(); } } #endregion } }