#region copyright //------------------------------------------------------------------------------ // 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充 // 此代码版权(除特别声明外的代码)归作者本人Diego所有 // 源代码使用协议遵循本仓库的开源协议及附加协议 // Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway // Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway // 使用文档:https://diego2098.gitee.io/thingsgateway-docs/ // QQ群:605534569 //------------------------------------------------------------------------------ #endregion using ThingsGateway.Foundation.Extension.Generic; using ThingsGateway.Foundation.Extension.String; namespace ThingsGateway.Foundation.Adapter.Modbus; /// /// PackHelper /// public class PackHelper { /// /// 打包变量,添加到 /// /// /// /// 最大打包长度 /// public static List LoadSourceRead(IReadWrite device, List deviceVariables, int maxPack) where T : IDeviceVariableSourceRead, new() where T2 : IDeviceVariableRunTime, new() { if (deviceVariables == null) throw new ArgumentNullException(nameof(deviceVariables)); var deviceVariableSourceReads = new List(); var byteConverter = device.ThingsGatewayBitConverter; //需要先剔除额外信息,比如dataformat等 foreach (var item in deviceVariables) { var address = item.VariableAddress; IThingsGatewayBitConverter transformParameter = ByteTransformUtil.GetTransByAddress(ref address, byteConverter); item.ThingsGatewayBitConverter = transformParameter; //item.VariableAddress = address; item.Index = device.GetBitOffset(item.VariableAddress); } var deviceVariableRunTimeGroups = deviceVariables.GroupBy(it => it.IntervalTime); foreach (var group in deviceVariableRunTimeGroups) { Dictionary map = group.ToDictionary(it => { var lastLen = it.DataTypeEnum.GetByteLength(); if (lastLen <= 0) { switch (it.DataTypeEnum) { case DataTypeEnum.String: lastLen = it.ThingsGatewayBitConverter.Length == null ? throw new("数据类型为字符串时,必须指定字符串长度,才能进行打包") : it.ThingsGatewayBitConverter.Length.Value; break; default: lastLen = 2; break; } } if (it.ThingsGatewayBitConverter.Length != null && it.DataTypeEnum != DataTypeEnum.String) { lastLen *= it.ThingsGatewayBitConverter.Length.Value; } var address = it.VariableAddress; if (address.IndexOf('.') > 0) { var addressSplits = address.SplitDot(); address = addressSplits.RemoveLast(1).ArrayToString("."); } var result = ModbusAddress.ParseFrom(address); result.ByteLength = lastLen; return result; }); //获取变量的地址 var modbusAddressList = map.Keys; //获取功能码 var functionCodes = modbusAddressList.Select(t => t.ReadFunction).Distinct(); foreach (var functionCode in functionCodes) { var modbusAddressSameFunList = modbusAddressList.Where(t => t.ReadFunction == functionCode); var stationNumbers = modbusAddressSameFunList.Select(t => t.Station).Distinct(); foreach (var stationNumber in stationNumbers) { var addressList = modbusAddressSameFunList .Where(t => t.Station == stationNumber) .ToDictionary(t => t, t => map[t]); var tempResult = LoadSourceRead(addressList, functionCode, group.Key, maxPack); deviceVariableSourceReads.AddRange(tempResult); } } } return deviceVariableSourceReads; } private static List LoadSourceRead(Dictionary addressList, int functionCode, int intervalTime, int maxPack) where T : IDeviceVariableSourceRead, new() where T2 : IDeviceVariableRunTime, new() { List sourceReads = new(); //按地址和长度排序 var orderByAddressEnd = addressList.Keys.OrderBy(it => it.AddressEnd); //按地址和长度排序 var orderByAddressStart = addressList.Keys.OrderBy(it => it.AddressStart); //地址最小,在循环中更改 var minAddress = orderByAddressStart.First().AddressStart; //地址最大 var maxAddress = orderByAddressStart.Last().AddressStart; while (maxAddress >= minAddress) { //最大的打包长度 int readLength = maxPack; if (functionCode == 1 || functionCode == 2) { readLength = maxPack * 8 * 2; } //获取当前的一组打包地址信息, var tempAddressEnd = orderByAddressEnd.Where(t => t.AddressEnd <= minAddress + readLength).ToList(); //起始地址 var startAddress = tempAddressEnd.OrderBy(it => it.AddressStart).First(); //读取寄存器长度 var sourceLen = tempAddressEnd.Last().AddressEnd - startAddress.AddressStart; T sourceRead = new() { TimerTick = new TimerTick(intervalTime), //这里只需要根据地址排序的第一个地址,作为实际打包报文中的起始地址 VariableAddress = startAddress.ToString(), Length = sourceLen }; foreach (var item in tempAddressEnd) { var readNode = addressList[item]; if ((functionCode == -1 || functionCode == 3 || functionCode == 4) && readNode.DataTypeEnum == DataTypeEnum.Boolean) { readNode.Index = ((item.AddressStart - startAddress.AddressStart) * 16) + readNode.Index; } else { if (functionCode == 1 || functionCode == 2) readNode.Index = item.AddressStart - startAddress.AddressStart + readNode.Index; else readNode.Index = ((item.AddressStart - startAddress.AddressStart) * 2) + readNode.Index; } sourceRead.DeviceVariableRunTimes.Add(readNode); addressList.Remove(item); } sourceReads.Add(sourceRead); if (orderByAddressEnd.Count() > 0) minAddress = orderByAddressStart.First().AddressStart; else break; } return sourceReads; } }