using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ModbusTest
{
public class ModbusManager
{
}
///
/// 读取任务单元
///
public class ReadBatchTask
{
public byte SlaveId { get; set; }
public byte FunctionCode { get; set; }
public ushort StartAddress { get; set; }
public ushort Quantity { get; set; }
///
/// 该批次包含的所有点位引用,用于后续解析映射
///
public List AssociatedPoints { get; set; } = new List();
}
public class ModbusBatchOptimizer
{
///
/// 将点位列表优化为批量读取任务
///
/// 所有待读取点位
/// 从站ID
/// 允许的最大地址间隙,超过此间隙则断开批次
public List Optimize(List points, byte slaveId, int maxGap = 5)
{
if (points == null || !points.Any()) return new List();
var tasks = new List();
// 1. 分组:按 从站ID(如果有多个) + 功能码 分组
// 这里简化假设只有一个 SlaveId,实际可再外层循环
var groups = points.GroupBy(p => p.FunctionCode);
foreach (var group in groups)
{
// 2. 排序:按地址升序
var sortedPoints = group.OrderBy(p => p.Address).ToList();
// 3. 合并连续地址
var batches = MergeContinuousPoints(sortedPoints, maxGap);
foreach (var batchPoints in batches)
{
var first = batchPoints.First();
var last = batchPoints.Last();
// 计算总读取长度:最后一个点的结束地址 - 起始地址
// 注意:last.Address + last.Quantity 是下一个可用地址,所以长度是差值
ushort startAddr = first.Address;
ushort endAddrExclusive = (ushort)(last.Address + last.Quantity);
ushort totalQty = (ushort)(endAddrExclusive - startAddr);
// NModbus 单次读取最大寄存器数通常限制为 125 (Function 3/4)
// 如果超过,需要进一步拆分(此处简化处理,实际生产需增加拆分逻辑)
if (totalQty > 125)
{
// TODO: 实现大批次拆分逻辑
throw new InvalidOperationException($"Batch size {totalQty} exceeds Modbus limit 125. Split logic needed.");
}
tasks.Add(new ReadBatchTask
{
SlaveId = slaveId,
FunctionCode = group.Key,
StartAddress = startAddr,
Quantity = totalQty,
AssociatedPoints = batchPoints
});
}
}
return tasks;
}
private List> MergeContinuousPoints(List sortedPoints, int maxGap)
{
var result = new List>();
if (!sortedPoints.Any()) return result;
var currentBatch = new List { sortedPoints[0] };
for (int i = 1; i < sortedPoints.Count; i++)
{
var prev = sortedPoints[i - 1];
var curr = sortedPoints[i];
// 前一个点的结束位置
int prevEnd = prev.Address + prev.Quantity;
// 如果当前点起始地址 与 前一个点结束位置 的差距在允许范围内
if (curr.Address <= prevEnd + maxGap)
{
currentBatch.Add(curr);
}
else
{
result.Add(currentBatch);
currentBatch = new List { curr };
}
}
result.Add(currentBatch);
return result;
}
}
///
/// Modbus 点位定义
///
public class ModbusPoint
{
///
/// 业务唯一ID
///
public string PointId { get; set; }
///
/// 寄存器起始地址 (0-based, 即协议中的 40001 对应地址 0)
///
public ushort Address { get; set; }
///
/// 占用寄存器数量 (Int16=1, Float32=2, Double64=4)
///
public ushort Quantity { get; set; } = 1;
///
/// 功能码: 3 (Read Holding), 4 (Read Input)
///
public byte FunctionCode { get; set; } = 3;
///
/// 数据类型
///
public DataTypeEnum DataType { get; set; } = DataTypeEnum.Int16;
///
/// 字节序 (针对多字节类型)
///
public ByteOrderEnum ByteOrder { get; set; } = ByteOrderEnum.ABCD;
///
/// 缩放系数: Result = Raw * Scale + Offset
///
public double Scale { get; set; } = 1.0;
///
/// 偏移量
///
public double Offset { get; set; } = 0.0;
///
/// 最新读取值
///
public object CurrentValue { get; set; }
///
/// 最后更新时间
///
public DateTime LastUpdateTime { get; set; }
}
public enum DataTypeEnum
{
Int16,
UInt16,
Int32,
UInt32,
Float32,
Double64
}
public enum ByteOrderEnum
{
ABCD, // Big Endian (标准)
BADC, // Byte Swap
CDAB, // Word Swap
DCBA // Little Endian
}
}