using System; using System.Net.Sockets; using System.Threading.Tasks; using Modbus.Device; namespace MembranePoreTester.Communication { public class ModbusTcpPlcService : IPlcService, IDisposable { private readonly PlcConfiguration _config; private TcpClient _tcpClient; private IModbusMaster _master; public ModbusTcpPlcService(PlcConfiguration config) { _config = config; } private async Task EnsureConnectedAsync() { if (_tcpClient == null || !_tcpClient.Connected) { _tcpClient = new TcpClient(); await _tcpClient.ConnectAsync(_config.IpAddress, _config.Port); _master = ModbusIpMaster.CreateIp(_tcpClient); } } // 读取两个连续的保持寄存器,转换为32位浮点数(假设大端模式) private async Task ReadFloatAsync(ushort startAddress) { await EnsureConnectedAsync(); // 读取两个寄存器(从站地址由配置指定) ushort[] registers = await _master.ReadHoldingRegistersAsync(_config.SlaveId, startAddress, 2); // 将两个16位寄存器合并为32位浮点数(大端) byte[] bytes = new byte[4]; bytes[0] = (byte)(registers[0] >> 8); bytes[1] = (byte)(registers[0] & 0xFF); bytes[2] = (byte)(registers[1] >> 8); bytes[3] = (byte)(registers[1] & 0xFF); if (BitConverter.IsLittleEndian) Array.Reverse(bytes); // 如果系统是小端,需要反转字节顺序 return BitConverter.ToSingle(bytes, 0); } public async Task ReadPressureAsync() => await ReadFloatAsync(_config.PressureRegister) * (float)_config.PressureFactor; public async Task ReadWetFlowAsync() => await ReadFloatAsync(_config.WetFlowRegister) * (float)_config.WetFlowFactor; public async Task ReadDryFlowAsync() => await ReadFloatAsync(_config.DryFlowRegister) * (float)_config.DryFlowFactor; public async Task WriteCoilAsync(ushort coilAddress, bool value) { await EnsureConnectedAsync(); await _master.WriteSingleCoilAsync(_config.SlaveId, coilAddress, value); } public async Task WriteRegisterAsync(ushort registerAddress, ushort value) { await EnsureConnectedAsync(); await _master.WriteSingleRegisterAsync(_config.SlaveId, registerAddress, value); } public async Task ReadCoilAsync(ushort coilAddress) { await EnsureConnectedAsync(); bool[] result = await _master.ReadCoilsAsync(_config.SlaveId, coilAddress, 1); return result[0]; } public async Task ReadHoldingRegistersAsync(ushort startAddress, ushort count) { await EnsureConnectedAsync(); return await _master.ReadHoldingRegistersAsync(_config.SlaveId, startAddress, count); } public async Task WriteSingleRegisterAsync(ushort registerAddress, ushort value) { await EnsureConnectedAsync(); await _master.WriteSingleRegisterAsync(_config.SlaveId, registerAddress, value); } // 新增读取压力(根据工位) public async Task ReadPressureAsync(int stationId) { ushort startAddress = stationId switch { 1 => _config.PressureRegisterStation1, 2 => _config.PressureRegisterStation2, 3 => _config.PressureRegisterStation3, _ => throw new ArgumentException("Invalid station") }; return await ReadFloatAsync(startAddress); } public void Dispose() { _master?.Dispose(); _tcpClient?.Close(); } } }