Files
ADP/DeviceCommand/Base/ModbusRtu.cs
2026-06-05 10:57:09 +08:00

164 lines
5.5 KiB
C#

using NModbus;
using NModbus.Serial;
using System;
using System.IO.Ports;
using System.Threading;
using System.Threading.Tasks;
namespace DeviceCommand.Base
{
public class ModbusRtu : IModbusDevice
{
public string PortName { get; private set; } = "COM1";
public int BaudRate { get; private set; } = 9600;
public int DataBits { get; private set; } = 8;
public StopBits StopBits { get; private set; } = StopBits.One;
public Parity Parity { get; private set; } = Parity.None;
public int ReadTimeout { get; private set; } = 3000;
public int WriteTimeout { get; private set; } = 3000;
private SerialPort _serialPort;
public IModbusMaster Modbus { get; private set; }
public bool IsConnected => _serialPort?.IsOpen ?? false;
protected readonly SemaphoreSlim _commLock = new(1, 1);
public ModbusRtu()
{
_serialPort = new SerialPort();
}
public void ConfigureDevice(string portName, int baudRate, int dataBits = 8, StopBits stopBits = StopBits.One, Parity parity = Parity.None, int readTimeout = 3000, int writeTimeout = 3000)
{
PortName = portName;
BaudRate = baudRate;
DataBits = dataBits;
StopBits = stopBits;
Parity = parity;
ReadTimeout = readTimeout;
WriteTimeout = writeTimeout;
}
public virtual async Task<bool> ConnectAsync(CancellationToken ct = default)
{
await _commLock.WaitAsync(ct);
try
{
if (_serialPort.IsOpen)
_serialPort.Close();
_serialPort.PortName = PortName;
_serialPort.BaudRate = BaudRate;
_serialPort.DataBits = DataBits;
_serialPort.StopBits = StopBits;
_serialPort.Parity = Parity;
_serialPort.ReadTimeout = ReadTimeout;
_serialPort.WriteTimeout = WriteTimeout;
_serialPort.Open();
Modbus = new ModbusFactory().CreateRtuMaster(_serialPort);
return true;
}
finally
{
_commLock.Release();
}
}
public virtual void Close()
{
if (_serialPort.IsOpen)
_serialPort.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.FromMilliseconds(WriteTimeout), 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.FromMilliseconds(WriteTimeout), ct);
}
finally
{
_commLock.Release();
}
}
public async Task<ushort[]> ReadHoldingRegistersAsync(byte slaveAddress, ushort startAddress, ushort numberOfPoints, CancellationToken ct = default)
{
await _commLock.WaitAsync(ct);
try
{
return await Modbus.ReadHoldingRegistersAsync(slaveAddress, startAddress, numberOfPoints)
.WaitAsync(TimeSpan.FromMilliseconds(ReadTimeout), ct);
}
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.FromMilliseconds(WriteTimeout), ct);
}
finally
{
_commLock.Release();
}
}
public async Task<bool[]> ReadCoilsAsync(byte slaveAddress, ushort startAddress, ushort numberOfPoints, CancellationToken ct = default)
{
await _commLock.WaitAsync(ct);
try
{
return await Modbus.ReadCoilsAsync(slaveAddress, startAddress, numberOfPoints)
.WaitAsync(TimeSpan.FromMilliseconds(ReadTimeout), ct);
}
finally
{
_commLock.Release();
}
}
public async Task<ushort[]> ReadInputRegistersAsync(byte slaveAddress, ushort startAddress, ushort numberOfPoints, CancellationToken ct = default)
{
await _commLock.WaitAsync(ct);
try
{
return await Modbus.ReadInputRegistersAsync(slaveAddress, startAddress, numberOfPoints)
.WaitAsync(TimeSpan.FromMilliseconds(ReadTimeout), ct);
}
finally
{
_commLock.Release();
}
}
public void Dispose()
{
_serialPort?.Dispose();
_commLock?.Dispose();
}
}
}