using Common.Attributes; using DeviceCommand.Base; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace DeviceCommand.Device { [BOBCommand] public class EAEL9080:ModbusTcp { public EAEL9080() { ConfigureDevice("127.0.0.1", 502, 3000, 3000); ConnectAsync(); } #region 一、基础控制与远程模式寄存器 public async Task SetRemoteControlAsync(bool activate, byte slaveAddress = 1, CancellationToken ct = default) { ushort value = (ushort)(activate ? 0xFF00 : 0x0000); await WriteSingleRegisterAsync(slaveAddress, 402, value, ct); } public async Task SetOutputAsync(bool on, byte slaveAddress = 1, CancellationToken ct = default) { ushort value = (ushort)(on ? 0xFF00 : 0x0000); await WriteSingleRegisterAsync(slaveAddress, 405, value, ct); } public async Task SetWorkModeAsync(bool useResistanceMode, byte slaveAddress = 1, CancellationToken ct = default) { ushort value = (ushort)(useResistanceMode ? 0xFF00 : 0x0000); await WriteSingleRegisterAsync(slaveAddress, 409, value, ct); } public async Task ResetAlarmAsync(byte slaveAddress = 1, CancellationToken ct = default) { await WriteSingleRegisterAsync(slaveAddress, 411, 0xFF00, ct); } public async Task WriteUserTextAsync(string text, byte slaveAddress = 1, CancellationToken ct = default) { if (string.IsNullOrEmpty(text)) return; text = text.Length > 40 ? text[..40] : text; int frameCount = (int)Math.Ceiling(text.Length / 4.0); for (int i = 0; i < frameCount; i++) { string frame = text.Substring(i * 4, Math.Min(4, text.Length - i * 4)); ushort[] values = new ushort[frame.Length]; for (int j = 0; j < frame.Length; j++) { values[j] = frame[j]; } await WriteMultipleRegistersAsync(slaveAddress, (ushort)(171 + i), values, ct); } } public async Task QueryRemoteControlAsync(byte slaveAddress = 1, CancellationToken ct = default) { ushort[] result = await ReadHoldingRegistersAsync(slaveAddress, 402, 1, ct); return result[0] == 0xFF00; } public async Task QueryOutputAsync(byte slaveAddress = 1, CancellationToken ct = default) { ushort[] result = await ReadHoldingRegistersAsync(slaveAddress, 405, 1, ct); return result[0] == 0xFF00; } public async Task QueryWorkModeAsync(byte slaveAddress = 1, CancellationToken ct = default) { ushort[] result = await ReadHoldingRegistersAsync(slaveAddress, 409, 1, ct); return result[0] == 0xFF00; // true 表示 UIR(电阻模式),false 表示 UIP } public async Task ReadUserTextAsync(byte slaveAddress = 1, int length = 40, CancellationToken ct = default) { int frameCount = (int)Math.Ceiling(length / 4.0); ushort[] textValues = new ushort[length]; for (int i = 0; i < frameCount; i++) { ushort[] frame = await ReadHoldingRegistersAsync(slaveAddress, (ushort)(171 + i), 4, ct); for (int j = 0; j < frame.Length && (i * 4 + j) < length; j++) { textValues[i * 4 + j] = frame[j]; } } return textValues; } #endregion #region 二、电压 / 电流 / 功率 / 电阻设定值寄存器 public async Task SetVoltageAsync(double voltage, double ratedVoltage, byte slaveAddress = 1, CancellationToken ct = default) { ushort value = (ushort)(voltage / ratedVoltage * 0xCCCC); await WriteSingleRegisterAsync(slaveAddress, 500, value, ct); } public async Task GetVoltageAsync(double ratedVoltage, byte slaveAddress = 1, CancellationToken ct = default) { ushort[] reg = await ReadHoldingRegistersAsync(slaveAddress, 500, 1, ct); return reg[0] / (double)0xCCCC * ratedVoltage; } public async Task SetCurrentAsync(double current, double ratedCurrent, byte slaveAddress = 1, CancellationToken ct = default) { ushort value = (ushort)(current / ratedCurrent * 0xCCCC); await WriteSingleRegisterAsync(slaveAddress, 501, value, ct); } public async Task GetCurrentAsync(double ratedCurrent, byte slaveAddress = 1, CancellationToken ct = default) { ushort[] reg = await ReadHoldingRegistersAsync(slaveAddress, 501, 1, ct); return reg[0] / (double)0xCCCC * ratedCurrent; } public async Task SetPowerAsync(double power, double ratedPower, byte slaveAddress = 1, CancellationToken ct = default) { ushort value = (ushort)(power / ratedPower * 0xCCCC); await WriteSingleRegisterAsync(slaveAddress, 502, value, ct); } public async Task GetPowerAsync(double ratedPower, byte slaveAddress = 1, CancellationToken ct = default) { ushort[] reg = await ReadHoldingRegistersAsync(slaveAddress, 502, 1, ct); return reg[0] / (double)0xCCCC * ratedPower; } public async Task SetResistanceAsync(double resistance, double maxResistance, byte slaveAddress = 1, CancellationToken ct = default) { ushort value = (ushort)(resistance / maxResistance * 0xCCCC); await WriteSingleRegisterAsync(slaveAddress, 503, value, ct); } public async Task GetResistanceAsync(double maxResistance, byte slaveAddress = 1, CancellationToken ct = default) { ushort[] reg = await ReadHoldingRegistersAsync(slaveAddress, 503, 1, ct); return reg[0] / (double)0xCCCC * maxResistance; } // sink 模式示例写方法 public async Task SetSinkPowerAsync(double power, double sinkRatedPower, byte slaveAddress = 1, CancellationToken ct = default) { ushort value = (ushort)(power / sinkRatedPower * 0xCCCC); await WriteSingleRegisterAsync(slaveAddress, 498, value, ct); } public async Task SetSinkCurrentAsync(double current, double sinkRatedCurrent, byte slaveAddress = 1, CancellationToken ct = default) { ushort value = (ushort)(current / sinkRatedCurrent * 0xCCCC); await WriteSingleRegisterAsync(slaveAddress, 499, value, ct); } public async Task SetSinkResistanceAsync(double resistance, double sinkMaxResistance, byte slaveAddress = 1, CancellationToken ct = default) { ushort value = (ushort)(resistance / sinkMaxResistance * 0xCCCC); await WriteSingleRegisterAsync(slaveAddress, 504, value, ct); } // 读方法 public async Task GetSinkPowerAsync(double sinkRatedPower, byte slaveAddress = 1, CancellationToken ct = default) { ushort[] reg = await ReadHoldingRegistersAsync(slaveAddress, 498, 1, ct); return reg[0] / (double)0xCCCC * sinkRatedPower; } public async Task GetSinkCurrentAsync(double sinkRatedCurrent, byte slaveAddress = 1, CancellationToken ct = default) { ushort[] reg = await ReadHoldingRegistersAsync(slaveAddress, 499, 1, ct); return reg[0] / (double)0xCCCC * sinkRatedCurrent; } public async Task GetSinkResistanceAsync(double sinkMaxResistance, byte slaveAddress = 1, CancellationToken ct = default) { ushort[] reg = await ReadHoldingRegistersAsync(slaveAddress, 504, 1, ct); return reg[0] / (double)0xCCCC * sinkMaxResistance; } #endregion #region 三、设备状态与实际值查询寄存器 /// /// 读取设备状态寄存器(32 位) /// Bit 7:DC 输出/输入开启 /// Bit 10:远程控制激活 /// Bit 12:sink 模式 /// public async Task ReadDeviceStatusAsync(byte slaveAddress = 1, CancellationToken ct = default) { ushort[] reg = await ReadHoldingRegistersAsync(slaveAddress, 505, 2, ct); // 32位寄存器 = 2 x 16位 return (uint)(reg[0] << 16 | reg[1]); } public async Task IsDcOnAsync(byte slaveAddress = 1, CancellationToken ct = default) { uint status = await ReadDeviceStatusAsync(slaveAddress, ct); return (status & (1 << 7)) != 0; } public async Task IsRemoteActiveAsync(byte slaveAddress = 1, CancellationToken ct = default) { uint status = await ReadDeviceStatusAsync(slaveAddress, ct); return (status & (1 << 10)) != 0; } public async Task IsSinkModeActiveAsync(byte slaveAddress = 1, CancellationToken ct = default) { uint status = await ReadDeviceStatusAsync(slaveAddress, ct); return (status & (1 << 12)) != 0; } /// /// 读取实际电压值(单位 V) /// 公式: 实际值 = 寄存器值 / 0xCCCC * 额定电压 /// public async Task ReadActualVoltageAsync(double ratedVoltage, byte slaveAddress = 1, CancellationToken ct = default) { ushort[] reg = await ReadHoldingRegistersAsync(slaveAddress, 507, 1, ct); return reg[0] / (double)0xCCCC * ratedVoltage; } /// /// 读取实际电流值(单位 A) /// sink 模式下可能为负值,需要根据 Bit 12 判断 /// public async Task ReadActualCurrentAsync(double ratedCurrent, byte slaveAddress = 1, CancellationToken ct = default) { ushort[] reg = await ReadHoldingRegistersAsync(slaveAddress, 508, 1, ct); double current = reg[0] / (double)0xCCCC * ratedCurrent; if (await IsSinkModeActiveAsync(slaveAddress, ct)) current = -current; // sink 模式电流为负 return current; } /// /// 读取实际功率值(单位 W) /// sink 模式下可能为负值 /// public async Task ReadActualPowerAsync(double ratedPower, byte slaveAddress = 1, CancellationToken ct = default) { ushort[] reg = await ReadHoldingRegistersAsync(slaveAddress, 509, 1, ct); double power = reg[0] / (double)0xCCCC * ratedPower; if (await IsSinkModeActiveAsync(slaveAddress, ct)) power = -power; return power; } /// /// 读取额定电压(IEEE 754 float) /// public async Task ReadRatedVoltageAsync(byte slaveAddress = 1, CancellationToken ct = default) { ushort[] reg = await ReadHoldingRegistersAsync(slaveAddress, 121, 2, ct); byte[] bytes = new byte[4]; bytes[0] = (byte)(reg[1] & 0xFF); bytes[1] = (byte)(reg[1] >> 8); bytes[2] = (byte)(reg[0] & 0xFF); bytes[3] = (byte)(reg[0] >> 8); return BitConverter.ToSingle(bytes, 0); } /// /// 读取额定电流(IEEE 754 float) /// public async Task ReadRatedCurrentAsync(byte slaveAddress = 1, CancellationToken ct = default) { ushort[] reg = await ReadHoldingRegistersAsync(slaveAddress, 122, 2, ct); byte[] bytes = new byte[4]; bytes[0] = (byte)(reg[1] & 0xFF); bytes[1] = (byte)(reg[1] >> 8); bytes[2] = (byte)(reg[0] & 0xFF); bytes[3] = (byte)(reg[0] >> 8); return BitConverter.ToSingle(bytes, 0); } /// /// 读取额定功率(IEEE 754 float) /// public async Task ReadRatedPowerAsync(byte slaveAddress = 1, CancellationToken ct = default) { ushort[] reg = await ReadHoldingRegistersAsync(slaveAddress, 123, 2, ct); byte[] bytes = new byte[4]; bytes[0] = (byte)(reg[1] & 0xFF); bytes[1] = (byte)(reg[1] >> 8); bytes[2] = (byte)(reg[0] & 0xFF); bytes[3] = (byte)(reg[0] >> 8); return BitConverter.ToSingle(bytes, 0); } #endregion #region 四、保护与报警相关寄存器 /// /// 设置过压保护(OVP)阈值 /// public async Task SetOverVoltageLimitAsync(double voltage, double ratedVoltage, byte slaveAddress = 1, CancellationToken ct = default) { ushort value = (ushort)(voltage / ratedVoltage * 0xCCCC); await WriteSingleRegisterAsync(slaveAddress, 510, value, ct); } /// /// 读取过压保护(OVP)阈值 /// public async Task ReadOverVoltageLimitAsync(double ratedVoltage, byte slaveAddress = 1, CancellationToken ct = default) { ushort[] reg = await ReadHoldingRegistersAsync(slaveAddress, 510, 1, ct); return reg[0] / (double)0xCCCC * ratedVoltage; } /// /// 设置过流保护(OCP)阈值 /// public async Task SetOverCurrentLimitAsync(double current, double ratedCurrent, byte slaveAddress = 1, CancellationToken ct = default) { ushort value = (ushort)(current / ratedCurrent * 0xCCCC); await WriteSingleRegisterAsync(slaveAddress, 511, value, ct); } /// /// 读取过流保护(OCP)阈值 /// public async Task ReadOverCurrentLimitAsync(double ratedCurrent, byte slaveAddress = 1, CancellationToken ct = default) { ushort[] reg = await ReadHoldingRegistersAsync(slaveAddress, 511, 1, ct); return reg[0] / (double)0xCCCC * ratedCurrent; } /// /// 设置过功率保护(OPP)阈值 /// public async Task SetOverPowerLimitAsync(double power, double ratedPower, byte slaveAddress = 1, CancellationToken ct = default) { ushort value = (ushort)(power / ratedPower * 0xCCCC); await WriteSingleRegisterAsync(slaveAddress, 512, value, ct); } /// /// 读取过功率保护(OPP)阈值 /// public async Task ReadOverPowerLimitAsync(double ratedPower, byte slaveAddress = 1, CancellationToken ct = default) { ushort[] reg = await ReadHoldingRegistersAsync(slaveAddress, 512, 1, ct); return reg[0] / (double)0xCCCC * ratedPower; } /// /// 读取 OVP 报警计数器,读取后复位 /// public async Task ReadOVPCountAsync(byte slaveAddress = 1, CancellationToken ct = default) { ushort[] reg = await ReadHoldingRegistersAsync(slaveAddress, 520, 1, ct); return reg[0]; } /// /// 读取 OCP 报警计数器 /// public async Task ReadOCPCountAsync(byte slaveAddress = 1, CancellationToken ct = default) { ushort[] reg = await ReadHoldingRegistersAsync(slaveAddress, 521, 1, ct); return reg[0]; } /// /// 读取 OPP 报警计数器 /// public async Task ReadOPPCountAsync(byte slaveAddress = 1, CancellationToken ct = default) { ushort[] reg = await ReadHoldingRegistersAsync(slaveAddress, 522, 1, ct); return reg[0]; } /// /// 读取过温(OT)报警计数器 /// public async Task ReadOTCountAsync(byte slaveAddress = 1, CancellationToken ct = default) { ushort[] reg = await ReadHoldingRegistersAsync(slaveAddress, 523, 1, ct); return reg[0]; } #endregion #region 五、函数发生器与特殊功能寄存器 // 寄存器 850:函数发生器启动/停止 public async Task SetFunctionGeneratorAsync(bool start, byte slaveAddress = 1, CancellationToken ct = default) { ushort value = start ? (ushort)0xFF00 : (ushort)0x0000; await WriteSingleRegisterAsync(slaveAddress, 850, value, ct); } public async Task ReadFunctionGeneratorAsync(byte slaveAddress = 1, CancellationToken ct = default) { ushort[] reg = await ReadHoldingRegistersAsync(slaveAddress, 850, 1, ct); return reg[0] == 0xFF00; } // 寄存器 851:函数发生器作用于电压 public async Task SetFunctionVoltageParamAsync(byte slaveAddress = 1, CancellationToken ct = default) { await WriteSingleRegisterAsync(slaveAddress, 851, 0xFF00, ct); } public async Task ReadFunctionVoltageParamAsync(byte slaveAddress = 1, CancellationToken ct = default) { ushort[] reg = await ReadHoldingRegistersAsync(slaveAddress, 851, 1, ct); return reg[0] == 0xFF00; } // 寄存器 852:函数发生器作用于电流 public async Task SetFunctionCurrentParamAsync(byte slaveAddress = 1, CancellationToken ct = default) { await WriteSingleRegisterAsync(slaveAddress, 852, 0xFF00, ct); } public async Task ReadFunctionCurrentParamAsync(byte slaveAddress = 1, CancellationToken ct = default) { ushort[] reg = await ReadHoldingRegistersAsync(slaveAddress, 852, 1, ct); return reg[0] == 0xFF00; } // 寄存器 859~861:序列控制 public async Task SetSequenceStartPointAsync(ushort startPoint, byte slaveAddress = 1, CancellationToken ct = default) { if (startPoint < 1 || startPoint > 99) throw new ArgumentOutOfRangeException(nameof(startPoint)); await WriteSingleRegisterAsync(slaveAddress, 859, startPoint, ct); } public async Task ReadSequenceStartPointAsync(byte slaveAddress = 1, CancellationToken ct = default) { ushort[] reg = await ReadHoldingRegistersAsync(slaveAddress, 859, 1, ct); return reg[0]; } public async Task SetSequenceEndPointAsync(ushort endPoint, byte slaveAddress = 1, CancellationToken ct = default) { if (endPoint < 1 || endPoint > 99) throw new ArgumentOutOfRangeException(nameof(endPoint)); await WriteSingleRegisterAsync(slaveAddress, 860, endPoint, ct); } public async Task ReadSequenceEndPointAsync(byte slaveAddress = 1, CancellationToken ct = default) { ushort[] reg = await ReadHoldingRegistersAsync(slaveAddress, 860, 1, ct); return reg[0]; } public async Task SetSequenceLoopCountAsync(ushort loopCount, byte slaveAddress = 1, CancellationToken ct = default) { if (loopCount > 999) throw new ArgumentOutOfRangeException(nameof(loopCount)); await WriteSingleRegisterAsync(slaveAddress, 861, loopCount, ct); } public async Task ReadSequenceLoopCountAsync(byte slaveAddress = 1, CancellationToken ct = default) { ushort[] reg = await ReadHoldingRegistersAsync(slaveAddress, 861, 1, ct); return reg[0]; } // 寄存器 11000:MPP 跟踪模式 public async Task SetMPPModeAsync(ushort mode, byte slaveAddress = 1, CancellationToken ct = default) { if (mode != 0x0001 && mode != 0x0002 && mode != 0x0004) throw new ArgumentOutOfRangeException(nameof(mode)); await WriteSingleRegisterAsync(slaveAddress, 11000, mode, ct); } public async Task ReadMPPModeAsync(byte slaveAddress = 1, CancellationToken ct = default) { ushort[] reg = await ReadHoldingRegistersAsync(slaveAddress, 11000, 1, ct); return reg[0]; } #endregion } }