using Common.Attributes;
using DeviceCommand.Base;
using Model.Models;
using System;
using System.Threading;
using System.Threading.Tasks;
namespace DeviceCommand.Devices
{
///
/// MCc30W 水冷机(一拖三控制),基于 Modbus TCP 协议(MCx ModbusTCP)通信。
/// 支持 3 回路独立控制:出液温度/流量/压力的目标设定与实时读取、回路启停、
/// 预控温、控流/控压模式切换、自动回液、报警复位/消音及状态回读。
/// 多寄存器数值采用 IEEE754 浮点大端序编码(2 个 16 位寄存器)。
///
[ACPCommand]
public class MCc30W : ModbusTcp
{
// 默认配置 (可从 config 或 TcpConfig 注入)
private readonly byte _slaveId = 0x01; // 单元标识符
///
/// 构造函数,初始化 Modbus TCP 连接配置。
///
/// TCP 连接配置(IP、端口等)
public MCc30W(TcpConfig config) : base(config)
{
}
#region 1. 底层连接与字节序转换辅助
///
/// 将单精度浮点数转换为 Modbus 大端序 2个16位寄存器
///
private ushort[] FloatToRegisters(float value)
{
byte[] bytes = BitConverter.GetBytes(value);
if (BitConverter.IsLittleEndian) Array.Reverse(bytes);
return new ushort[]
{
BitConverter.ToUInt16(bytes, 0),
BitConverter.ToUInt16(bytes, 2)
};
}
///
/// 将 Modbus 大端序 2个16位寄存器转换回单精度浮点数
///
private float RegistersToFloat(ushort[] registers)
{
if (registers.Length < 2) return 0f;
byte[] bytes = new byte[4];
Buffer.BlockCopy(BitConverter.GetBytes(registers[0]), 0, bytes, 0, 2);
Buffer.BlockCopy(BitConverter.GetBytes(registers[1]), 0, bytes, 2, 2);
if (BitConverter.IsLittleEndian) Array.Reverse(bytes);
return BitConverter.ToSingle(bytes, 0);
}
///
/// 将 32位无符号整数转换为 Modbus 大端序 2个16位寄存器
///
private ushort[] UInt32ToRegisters(uint value)
{
byte[] bytes = BitConverter.GetBytes(value);
if (BitConverter.IsLittleEndian) Array.Reverse(bytes);
return new ushort[]
{
BitConverter.ToUInt16(bytes, 0),
BitConverter.ToUInt16(bytes, 2)
};
}
///
/// 将 Modbus 大端序 2个16位寄存器转换回 32位无符号整数
///
private uint RegistersToUInt32(ushort[] registers)
{
byte[] bytes = new byte[4];
Buffer.BlockCopy(BitConverter.GetBytes(registers[0]), 0, bytes, 0, 2);
Buffer.BlockCopy(BitConverter.GetBytes(registers[1]), 0, bytes, 2, 2);
if (BitConverter.IsLittleEndian) Array.Reverse(bytes);
return BitConverter.ToUInt32(bytes, 0);
}
#endregion
#region 2. 模拟量读写 API (支持 3 通道)
///
/// 设置指定回路的出液目标温度,写入对应回路的保持寄存器。
///
/// 回路编号 (1-3)
/// 出液目标温度,单位 ℃
/// 异步取消令牌
public virtual async Task 设置出液目标温度Async(int loop, float temperature, CancellationToken ct = default)
{
ushort address = (ushort)(0x0000 + (loop - 1) * 2);
ushort[] data = FloatToRegisters(temperature);
await WriteMultipleRegistersAsync(_slaveId, address, data, ct);
}
///
/// 设置指定回路的出液目标流量,写入对应回路的保持寄存器。
///
/// 回路编号 (1-3)
/// 出液目标流量,单位 L/min
/// 异步取消令牌
public virtual async Task 设置出液目标流量Async(int loop, float flow, CancellationToken ct = default)
{
ushort address = (ushort)(0x0008 + (loop - 1) * 2);
ushort[] data = FloatToRegisters(flow);
await WriteMultipleRegistersAsync(_slaveId, address, data, ct);
}
///
/// 设置指定回路的出液目标压力,写入对应回路的保持寄存器。
///
/// 回路编号 (1-3)
/// 出液目标压力,单位 kPa
/// 异步取消令牌
public virtual async Task 设置出液目标压力Async(int loop, float pressure, CancellationToken ct = default)
{
ushort address = (ushort)(0x000E + (loop - 1) * 2);
ushort[] data = FloatToRegisters(pressure);
await WriteMultipleRegistersAsync(_slaveId, address, data, ct);
}
///
/// 读取指定回路的当前出液温度。
///
/// 回路编号 (1-3)
/// 异步取消令牌
/// 当前出液温度,单位 ℃
[Monitorable("水冷机出液当前温度")]
public virtual async Task 读取出液当前温度Async(int loop, CancellationToken ct = default)
{
ushort address = (ushort)(0x0018 + (loop - 1) * 2);
ushort[] regs = await ReadHoldingRegistersAsync(_slaveId, address, 2, ct);
return RegistersToFloat(regs);
}
///
/// 读取指定回路的当前出液流量。
/// 注意:协议中三通道流量地址间隔为 0x08。
///
/// 回路编号 (1-3)
/// 异步取消令牌
/// 当前出液流量,单位 L/min
[Monitorable("水冷机出液当前流量")]
public virtual async Task 读取出液当前流量Async(int loop, CancellationToken ct = default)
{
ushort address = (ushort)(0x001E + (loop - 1) * 8);
ushort[] regs = await ReadHoldingRegistersAsync(_slaveId, address, 2, ct);
return RegistersToFloat(regs);
}
///
/// 读取指定回路的当前出液压力。
/// 注意:协议中三通道压力地址间隔为 0x08。
///
/// 回路编号 (1-3)
/// 异步取消令牌
/// 当前出液压力,单位 kPa
[Monitorable("水冷机出液当前压力")]
public virtual async Task 读取出液当前压力Async(int loop, CancellationToken ct = default)
{
ushort address = (ushort)(0x0020 + (loop - 1) * 8);
ushort[] regs = await ReadHoldingRegistersAsync(_slaveId, address, 2, ct);
return RegistersToFloat(regs);
}
///
/// 读取指定回路的当前回液压力(寄存器地址 0x0022 + (loop-1)*8)。
///
/// 回路编号 (1-3)
/// 异步取消令牌
/// 当前回液压力,单位 kPa
[Monitorable("水冷机回液当前压力")]
public virtual async Task 读取回液当前压力Async(int loop, CancellationToken ct = default)
{
ushort address = (ushort)(0x0022 + (loop - 1) * 8);
ushort[] regs = await ReadHoldingRegistersAsync(_slaveId, address, 2, ct);
return RegistersToFloat(regs);
}
///
/// 读取指定回路的当前回液温度(寄存器地址 0x0024 + (loop-1)*8)。
///
/// 回路编号 (1-3)
/// 异步取消令牌
/// 当前回液温度,单位 ℃
[Monitorable("水冷机回液当前温度")]
public virtual async Task 读取回液当前温度Async(int loop, CancellationToken ct = default)
{
ushort address = (ushort)(0x0024 + (loop - 1) * 8);
ushort[] regs = await ReadHoldingRegistersAsync(_slaveId, address, 2, ct);
return RegistersToFloat(regs);
}
///
/// 读取指定回路的外部温度反馈(寄存器地址 0x0036 + (loop-1)*2)。
///
/// 回路编号 (1-3)
/// 异步取消令牌
/// 外部温度反馈值,单位 ℃
[Monitorable("水冷机外部温度反馈")]
public virtual async Task 读取外部温度反馈Async(int loop, CancellationToken ct = default)
{
ushort address = (ushort)(0x0036 + (loop - 1) * 2);
ushort[] regs = await ReadHoldingRegistersAsync(_slaveId, address, 2, ct);
return RegistersToFloat(regs);
}
///
/// 读取指定回路的温变速率设定值(寄存器地址 0x0006 + (loop-1)*2)。
///
/// 回路编号 (1-3)
/// 异步取消令牌
/// 温变速率设定值,单位 ℃/min
[Monitorable("水冷机温变速率")]
public virtual async Task 读取温变速率Async(int loop, CancellationToken ct = default)
{
ushort address = (ushort)(0x0006 + (loop - 1) * 2);
ushort[] regs = await ReadHoldingRegistersAsync(_slaveId, address, 2, ct);
return RegistersToFloat(regs);
}
///
/// 读取回抽2流量目标值(固定寄存器地址 0x0016,不区分回路)。
///
/// 异步取消令牌
/// 回抽2流量目标值,单位 L/min
[Monitorable("水冷机回抽2流量目标值")]
public virtual async Task 读取回抽2流量目标值Async(CancellationToken ct = default)
{
ushort[] regs = await ReadHoldingRegistersAsync(_slaveId, 0x0016, 2, ct);
return RegistersToFloat(regs);
}
#endregion
#region 3. 系统状态与位控制 API (支持 3 通道)
///
/// 核心位操作方法:读取 -> 置位/复位 -> 写入系统状态控制寄存器 (0x0014)
///
private async Task SetControlBit(int bitIndex, bool isSet, CancellationToken ct = default)
{
// 1. 读取当前状态
ushort[] regs = await ReadHoldingRegistersAsync(_slaveId, 0x0014, 1, ct);
ushort currentState = regs[0];
// 2. 修改位
if (isSet)
currentState |= (ushort)(1 << bitIndex);
else
currentState &= (ushort)~(1 << bitIndex);
// 3. 写回
await WriteSingleRegisterAsync(_slaveId, 0x0014, currentState, ct);
}
///
/// 启动/停止指定回路(操作系统状态控制寄存器 0x0014 的 Bit 01/02/03)。
///
/// 回路编号 (1-3),分别对应 Bit 1/2/3
/// true: 启动回路, false: 停止回路
/// 异步取消令牌
/// 回路号不在 1-3 范围内时抛出
public virtual async Task 设置回路运行Async(int loop, bool enable, CancellationToken ct = default)
{
if (loop < 1 || loop > 3) throw new ArgumentOutOfRangeException(nameof(loop), "回路号必须为1, 2, 3");
await SetControlBit(loop, enable, ct); // 回路1->Bit1, 回路2->Bit2, 回路3->Bit3
}
///
/// 启动/停止指定回路的预控温(操作系统状态控制寄存器 0x0014 的 Bit 10/11/12)。
///
/// 回路编号 (1-3),分别对应 Bit 10/11/12
/// true: 开启预控温, false: 关闭预控温
/// 异步取消令牌
/// 回路号不在 1-3 范围内时抛出
public virtual async Task 设置回路预控温Async(int loop, bool enable, CancellationToken ct = default)
{
if (loop < 1 || loop > 3) throw new ArgumentOutOfRangeException(nameof(loop), "回路号必须为1, 2, 3");
await SetControlBit(9 + loop, enable, ct); // 回路1->Bit10, 回路2->Bit11, 回路3->Bit12
}
///
/// 设置指定回路的流量/压力控制模式(操作系统状态控制寄存器 0x0014 的 Bit 04/05/06)。
///
/// 回路编号 (1-3),分别对应 Bit 4/5/6
/// true: 控压模式, false: 控流模式
/// 异步取消令牌
/// 回路号不在 1-3 范围内时抛出
public virtual async Task 设置回路压力控制Async(int loop, bool isPressureControl, CancellationToken ct = default)
{
if (loop < 1 || loop > 3) throw new ArgumentOutOfRangeException(nameof(loop), "回路号必须为1, 2, 3");
await SetControlBit(3 + loop, isPressureControl, ct); // 回路1->Bit4, 回路2->Bit5, 回路3->Bit6
}
///
/// 报警复位(操作系统状态控制寄存器 0x0014 的 Bit 08),用于清除水冷机报警状态。
///
/// true: 置位报警复位位, false: 清除该位
/// 异步取消令牌
public virtual async Task 报警复位Async(bool enable, CancellationToken ct = default)
{
await SetControlBit(8, enable, ct);
}
///
/// 报警消音(操作系统状态控制寄存器 0x0014 的 Bit 09),用于关闭报警蜂鸣。
///
/// true: 置位消音位, false: 清除该位
/// 异步取消令牌
public virtual async Task 报警消音Async(bool enable, CancellationToken ct = default)
{
await SetControlBit(9, enable, ct);
}
///
/// 设置指定回路的自动回液开关(操作寄存器 0x0015 的 Bit 13/14/15)。
///
/// 回路编号 (1-3),分别对应 Bit 13/14/15
/// true: 开启自动回液, false: 关闭自动回液
/// 异步取消令牌
/// 回路号不在 1-3 范围内时抛出
public virtual async Task 设置回路自动回液Async(int loop, bool enable, CancellationToken ct = default)
{
if (loop < 1 || loop > 3) throw new ArgumentOutOfRangeException(nameof(loop), "回路号必须为1, 2, 3");
// 协议 Sheet2 中 0x0015 寄存器位定义:
// Bit 13 (Loop1), Bit 14 (Loop2), Bit 15 (Loop3)
int bitIndex = 12 + loop;
// 0x0015 控制寄存器逻辑
ushort[] regs = await ReadHoldingRegistersAsync(_slaveId, 0x0015, 1, ct);
ushort currentState = regs[0];
if (enable)
currentState |= (ushort)(1 << bitIndex);
else
currentState &= (ushort)~(1 << bitIndex);
await WriteSingleRegisterAsync(_slaveId, 0x0015, currentState, ct);
}
#endregion
#region 4. 状态回读 (报警、心跳、运行状态)
///
/// 读取心跳帧(寄存器 0x0044),心跳值持续变化,用于判断通讯是否正常。
///
/// 异步取消令牌
/// 32 位心跳计数值
[Monitorable("水冷机心跳帧")]
public virtual async Task 读心跳帧Async(CancellationToken ct = default)
{
ushort[] regs = await ReadHoldingRegistersAsync(_slaveId, 0x0044, 2, ct);
return RegistersToUInt32(regs);
}
///
/// 读取运行状态反馈(寄存器 0x0046),含各回路完成状态位(协议 Sheet5)。
///
/// 异步取消令牌
/// 32 位运行状态位图
[Monitorable("水冷机运行状态反馈")]
public virtual async Task 读运行状态反馈Async(CancellationToken ct = default)
{
ushort[] regs = await ReadHoldingRegistersAsync(_slaveId, 0x0046, 2, ct);
return RegistersToUInt32(regs);
}
///
/// 读取报警信息1(寄存器 0x003C),每一位对应一种报警类型。
///
/// 异步取消令牌
/// 32 位报警信息位图,0 表示无报警
[Monitorable("水冷机报警信息1")]
public virtual async Task 读报警信息1Async(CancellationToken ct = default)
{
ushort[] regs = await ReadHoldingRegistersAsync(_slaveId, 0x003C, 2, ct);
return RegistersToUInt32(regs);
}
///
/// 读取报警信息2(寄存器 0x003E),每一位对应一种报警类型。
///
/// 异步取消令牌
/// 32 位报警信息位图,0 表示无报警
[Monitorable("水冷机报警信息2")]
public virtual async Task 读报警信息2Async(CancellationToken ct = default)
{
ushort[] regs = await ReadHoldingRegistersAsync(_slaveId, 0x003E, 2, ct);
return RegistersToUInt32(regs);
}
#endregion
}
}