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 } }