BOB/DeviceCommand/Device/PSB11000.cs
2025-11-14 16:12:44 +08:00

483 lines
20 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using DeviceCommand.Base;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace DeviceCommand.Device
{
public class PSB11000: ModbusTcp
{
#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<bool> QueryRemoteControlAsync(byte slaveAddress = 1, CancellationToken ct = default)
{
ushort[] result = await ReadHoldingRegistersAsync(slaveAddress, 402, 1, ct);
return result[0] == 0xFF00;
}
public async Task<bool> QueryOutputAsync(byte slaveAddress = 1, CancellationToken ct = default)
{
ushort[] result = await ReadHoldingRegistersAsync(slaveAddress, 405, 1, ct);
return result[0] == 0xFF00;
}
public async Task<bool> 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<ushort[]> 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<double> 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<double> 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<double> 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<double> 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<double> 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<double> 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<double> 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
/// <summary>
/// 读取设备状态寄存器32 位)
/// Bit 7DC 输出/输入开启
/// Bit 10远程控制激活
/// Bit 12sink 模式
/// </summary>
public async Task<uint> 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<bool> IsDcOnAsync(byte slaveAddress = 1, CancellationToken ct = default)
{
uint status = await ReadDeviceStatusAsync(slaveAddress, ct);
return (status & (1 << 7)) != 0;
}
public async Task<bool> IsRemoteActiveAsync(byte slaveAddress = 1, CancellationToken ct = default)
{
uint status = await ReadDeviceStatusAsync(slaveAddress, ct);
return (status & (1 << 10)) != 0;
}
public async Task<bool> IsSinkModeActiveAsync(byte slaveAddress = 1, CancellationToken ct = default)
{
uint status = await ReadDeviceStatusAsync(slaveAddress, ct);
return (status & (1 << 12)) != 0;
}
/// <summary>
/// 读取实际电压值(单位 V
/// 公式: 实际值 = 寄存器值 / 0xCCCC * 额定电压
/// </summary>
public async Task<double> ReadActualVoltageAsync(double ratedVoltage, byte slaveAddress = 1, CancellationToken ct = default)
{
ushort[] reg = await ReadHoldingRegistersAsync(slaveAddress, 507, 1, ct);
return reg[0] / (double)0xCCCC * ratedVoltage;
}
/// <summary>
/// 读取实际电流值(单位 A
/// sink 模式下可能为负值,需要根据 Bit 12 判断
/// </summary>
public async Task<double> 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;
}
/// <summary>
/// 读取实际功率值(单位 W
/// sink 模式下可能为负值
/// </summary>
public async Task<double> 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;
}
/// <summary>
/// 读取额定电压IEEE 754 float
/// </summary>
public async Task<float> 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);
}
/// <summary>
/// 读取额定电流IEEE 754 float
/// </summary>
public async Task<float> 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);
}
/// <summary>
/// 读取额定功率IEEE 754 float
/// </summary>
public async Task<float> 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
/// <summary>
/// 设置过压保护OVP阈值
/// </summary>
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);
}
/// <summary>
/// 读取过压保护OVP阈值
/// </summary>
public async Task<double> ReadOverVoltageLimitAsync(double ratedVoltage, byte slaveAddress = 1, CancellationToken ct = default)
{
ushort[] reg = await ReadHoldingRegistersAsync(slaveAddress, 510, 1, ct);
return reg[0] / (double)0xCCCC * ratedVoltage;
}
/// <summary>
/// 设置过流保护OCP阈值
/// </summary>
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);
}
/// <summary>
/// 读取过流保护OCP阈值
/// </summary>
public async Task<double> ReadOverCurrentLimitAsync(double ratedCurrent, byte slaveAddress = 1, CancellationToken ct = default)
{
ushort[] reg = await ReadHoldingRegistersAsync(slaveAddress, 511, 1, ct);
return reg[0] / (double)0xCCCC * ratedCurrent;
}
/// <summary>
/// 设置过功率保护OPP阈值
/// </summary>
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);
}
/// <summary>
/// 读取过功率保护OPP阈值
/// </summary>
public async Task<double> ReadOverPowerLimitAsync(double ratedPower, byte slaveAddress = 1, CancellationToken ct = default)
{
ushort[] reg = await ReadHoldingRegistersAsync(slaveAddress, 512, 1, ct);
return reg[0] / (double)0xCCCC * ratedPower;
}
/// <summary>
/// 读取 OVP 报警计数器,读取后复位
/// </summary>
public async Task<ushort> ReadOVPCountAsync(byte slaveAddress = 1, CancellationToken ct = default)
{
ushort[] reg = await ReadHoldingRegistersAsync(slaveAddress, 520, 1, ct);
return reg[0];
}
/// <summary>
/// 读取 OCP 报警计数器
/// </summary>
public async Task<ushort> ReadOCPCountAsync(byte slaveAddress = 1, CancellationToken ct = default)
{
ushort[] reg = await ReadHoldingRegistersAsync(slaveAddress, 521, 1, ct);
return reg[0];
}
/// <summary>
/// 读取 OPP 报警计数器
/// </summary>
public async Task<ushort> ReadOPPCountAsync(byte slaveAddress = 1, CancellationToken ct = default)
{
ushort[] reg = await ReadHoldingRegistersAsync(slaveAddress, 522, 1, ct);
return reg[0];
}
/// <summary>
/// 读取过温OT报警计数器
/// </summary>
public async Task<ushort> 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<bool> 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<bool> 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<bool> 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<ushort> 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<ushort> 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<ushort> ReadSequenceLoopCountAsync(byte slaveAddress = 1, CancellationToken ct = default)
{
ushort[] reg = await ReadHoldingRegistersAsync(slaveAddress, 861, 1, ct);
return reg[0];
}
// 寄存器 11000MPP 跟踪模式
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<ushort> ReadMPPModeAsync(byte slaveAddress = 1, CancellationToken ct = default)
{
ushort[] reg = await ReadHoldingRegistersAsync(slaveAddress, 11000, 1, ct);
return reg[0];
}
#endregion
}
}