/// <summary> /// 组合地址 /// </summary> /// <param name="addresses">需要组合的地址</param> /// <returns>组合后的地址</returns> public override IEnumerable <CommunicationUnit <TKey> > Combine(IEnumerable <AddressUnit <TKey> > addresses) { var groupedAddresses = from address in addresses orderby AddressHelper.GetProtocalCoordinate(address.Address, address.SubAddress, AddressTranslator.GetAreaByteLength(address.Area)) group address by address.Area into grouped select grouped; var ans = new List <CommunicationUnit <TKey> >(); foreach (var groupedAddress in groupedAddresses) { var area = groupedAddress.Key; double initNum = -1; double preNum = -1; Type preType = null; var originalAddresses = new List <AddressUnit <TKey> >(); var orderedAddresses = groupedAddress.OrderBy( address => AddressHelper.GetProtocalCoordinate(address.Address, address.SubAddress, AddressTranslator.GetAreaByteLength(address.Area))); foreach (var address in orderedAddresses) { if (initNum < 0) { initNum = AddressHelper.GetProtocalCoordinate(address.Address, address.SubAddress, AddressTranslator.GetAreaByteLength(address.Area)); originalAddresses.Add(address); } else { if (AddressHelper.GetProtocalCoordinate(address.Address, address.SubAddress, AddressTranslator.GetAreaByteLength(address.Area)) < AddressHelper.GetProtocalCoordinateNextPosition(preNum, preType, AddressTranslator.GetAreaByteLength(address.Area))) { originalAddresses.Add(address); //如果当前地址的末尾被记录,表示地址被记录的地址域覆盖,这个地址没有记录的必要 if (AddressHelper.GetProtocalCoordinateNextPosition( AddressHelper.GetProtocalCoordinate(address.Address, address.SubAddress, AddressTranslator.GetAreaByteLength(address.Area)), address.DataType, AddressTranslator.GetAreaByteLength(address.Area)) <= AddressHelper.GetProtocalCoordinateNextPosition(preNum, preType, AddressTranslator.GetAreaByteLength(address.Area))) { continue; } } else if (AddressHelper.GetProtocalCoordinate(address.Address, address.SubAddress, AddressTranslator.GetAreaByteLength(address.Area)) > AddressHelper.GetProtocalCoordinateNextPosition(preNum, preType, AddressTranslator.GetAreaByteLength(address.Area))) { ans.Add(new CommunicationUnit <TKey> { Area = area, Address = (int)Math.Floor(initNum), GetCount = (int) Math.Ceiling( AddressHelper.MapProtocalGetCountToAbstractByteCount( preNum - (int)Math.Floor(initNum), AddressTranslator.GetAreaByteLength(address.Area), BigEndianValueHelper.Instance.ByteLength[preType.FullName])), DataType = typeof(byte), OriginalAddresses = originalAddresses.ToList() }); initNum = address.Address; originalAddresses.Clear(); originalAddresses.Add(address); } else { //地址连续,压入当前记录的结果 originalAddresses.Add(address); } } //把当前地址变为上一个地址 preNum = AddressHelper.GetProtocalCoordinate(address.Address, address.SubAddress, AddressTranslator.GetAreaByteLength(address.Area)); preType = address.DataType; } //最后一个地址域压入返回结果 ans.Add(new CommunicationUnit <TKey> { Area = area, Address = (int)Math.Floor(initNum), GetCount = (int) Math.Ceiling( AddressHelper.MapProtocalGetCountToAbstractByteCount( preNum - (int)Math.Floor(initNum), AddressTranslator.GetAreaByteLength(area), BigEndianValueHelper.Instance.ByteLength[preType.FullName])), DataType = typeof(byte), OriginalAddresses = originalAddresses.ToList() }); } var newAns = new List <CommunicationUnit <TKey> >(); foreach (var communicationUnit in ans) { var oldByteCount = communicationUnit.GetCount * BigEndianValueHelper.Instance.ByteLength[communicationUnit.DataType.FullName]; while (oldByteCount * BigEndianValueHelper.Instance.ByteLength[communicationUnit.DataType.FullName] > MaxLength) { var newOriginalAddresses = new List <AddressUnit <TKey> >(); var oldOriginalAddresses = communicationUnit.OriginalAddresses.ToList(); var newByteCount = 0.0; do { var currentAddressUnit = oldOriginalAddresses.First(); newByteCount += BigEndianValueHelper.Instance.ByteLength[currentAddressUnit.DataType.FullName]; if (newByteCount > MaxLength) { break; } oldByteCount -= BigEndianValueHelper.Instance.ByteLength[currentAddressUnit.DataType.FullName]; newOriginalAddresses.Add(currentAddressUnit); oldOriginalAddresses.RemoveAt(0); } while (newByteCount < MaxLength); var newCommunicationUnit = new CommunicationUnit <TKey> { Area = communicationUnit.Area, Address = communicationUnit.Address, SubAddress = communicationUnit.SubAddress, DataType = communicationUnit.DataType, GetCount = (int) Math.Ceiling(newByteCount / BigEndianValueHelper.Instance.ByteLength[communicationUnit.DataType.FullName]), OriginalAddresses = newOriginalAddresses }; newAns.Add(newCommunicationUnit); } communicationUnit.GetCount = (int) Math.Ceiling(oldByteCount / BigEndianValueHelper.Instance.ByteLength[communicationUnit.DataType.FullName]); newAns.Add(communicationUnit); } return(newAns); }
/// <summary> /// 写入数据 /// </summary> /// <param name="setDataType">写入类型</param> /// <param name="values">需要写入的数据字典,当写入类型为Address时,键为需要写入的地址,当写入类型为CommunicationTag时,键为需要写入的单元的描述</param> /// <returns>是否写入成功</returns> public async Task <bool> SetDatasAsync(MachineSetDataType setDataType, Dictionary <string, double> values) { try { //检测并连接设备 if (!BaseUtility.IsConnected) { await BaseUtility.ConnectAsync(); } //如果设备无法连接,终止 if (!BaseUtility.IsConnected) { return(false); } var addresses = new List <AddressUnit>(); //遍历每个要设置的值 foreach (var value in values) { //根据设置类型找到对应的地址描述 AddressUnit address = null; switch (setDataType) { case MachineSetDataType.Address: { address = GetAddresses.SingleOrDefault( p => AddressFormater.FormatAddress(p.Area, p.Address, p.SubAddress) == value.Key || (p.DataType != typeof(bool) && AddressFormater.FormatAddress(p.Area, p.Address) == value.Key)); break; } case MachineSetDataType.CommunicationTag: { address = GetAddresses.SingleOrDefault(p => p.CommunicationTag == value.Key); break; } case MachineSetDataType.Name: { address = GetAddresses.SingleOrDefault(p => p.Name == value.Key); break; } } //地址为空报错 if (address == null) { Console.WriteLine($"Machine {ConnectionToken} Address {value.Key} doesn't exist."); continue; } //不能写报错 if (!address.CanWrite) { Console.WriteLine($"Machine {ConnectionToken} Address {value.Key} cannot write."); continue; } addresses.Add(address); } //将地址编码成与实际设备通讯的地址 var communcationUnits = AddressCombinerSet.Combine(addresses); //遍历每条通讯的连续地址 foreach (var communicateAddress in communcationUnits) { //编码开始地址 var addressStart = AddressFormater.FormatAddress(communicateAddress.Area, communicateAddress.Address); var datasReturn = await BaseUtility.GetDatasAsync( AddressFormater.FormatAddress(communicateAddress.Area, communicateAddress.Address, 0), (int) Math.Ceiling(communicateAddress.GetCount * BigEndianValueHelper.Instance.ByteLength[ communicateAddress.DataType.FullName])); var valueHelper = ValueHelper.GetInstance(BaseUtility.Endian); //如果设备本身能获取到数据但是没有数据 var datas = datasReturn; //如果没有数据,终止 if (datas == null || datas.Length < (int) Math.Ceiling(communicateAddress.GetCount * BigEndianValueHelper.Instance.ByteLength[ communicateAddress.DataType.FullName])) { return(false); } foreach (var addressUnit in communicateAddress.OriginalAddresses) { //字节坐标地址 var byteCount = AddressHelper.MapProtocalGetCountToAbstractByteCount( addressUnit.Address - communicateAddress.Address + addressUnit.SubAddress * 0.125 / AddressTranslator.GetAreaByteLength(communicateAddress.Area), AddressTranslator.GetAreaByteLength(communicateAddress.Area), 0); //字节坐标主地址 var mainByteCount = (int)byteCount; //字节坐标自地址 var localByteCount = (int)((byteCount - (int)byteCount) * 8); //协议坐标地址 var localPos = byteCount / AddressTranslator.GetAreaByteLength(communicateAddress.Area); //协议坐标子地址 var subPos = (int) ((localPos - (int)localPos) / (0.125 / AddressTranslator.GetAreaByteLength(communicateAddress.Area))); //协议主地址字符串 var address = AddressFormater.FormatAddress(communicateAddress.Area, communicateAddress.Address + (int)localPos, subPos); //协议完整地址字符串 var address2 = subPos != 0 ? null : AddressFormater.FormatAddress(communicateAddress.Area, communicateAddress.Address + (int)localPos); //获取写入类型 var dataType = addressUnit.DataType; switch (setDataType) { case MachineSetDataType.Address: { //获取要写入的值 var value = values.SingleOrDefault( p => p.Key == address || (address2 != null && p.Key == address2)); //将要写入的值加入队列 var data = Convert.ChangeType(value.Value / addressUnit.Zoom, dataType); if (!valueHelper.SetValue(datas, mainByteCount, localByteCount, data)) { return(false); } break; } case MachineSetDataType.CommunicationTag: { var value = values.SingleOrDefault(p => p.Key == addressUnit.CommunicationTag); var data = Convert.ChangeType(value.Value / addressUnit.Zoom, dataType); if (!valueHelper.SetValue(datas, mainByteCount, localByteCount, data)) { return(false); } break; } case MachineSetDataType.Name: { var value = values.SingleOrDefault(p => p.Key == addressUnit.Name); var data = Convert.ChangeType(value.Value / addressUnit.Zoom, dataType); if (!valueHelper.SetValue(datas, mainByteCount, localByteCount, data)) { return(false); } break; } } } //写入数据 await BaseUtility.SetDatasAsync(addressStart, valueHelper.ByteArrayToObjectArray(datas, new KeyValuePair <Type, int>(communicateAddress.DataType, communicateAddress.GetCount))); } //如果不保持连接,断开连接 if (!KeepConnect) { BaseUtility.Disconnect(); } } catch (Exception e) { Console.WriteLine(ConnectionToken + " " + e.Message); return(false); } return(true); }
public override IEnumerable <CommunicationUnit> Combine(IEnumerable <AddressUnit> addresses) { //按从小到大的顺序对地址进行排序 var groupedAddresses = from address in addresses orderby AddressHelper.GetProtocalCoordinate(address.Address, address.SubAddress, AddressTranslator.GetAreaByteLength(address.Area)) group address by address.Area into grouped select grouped; var ans = new List <CommunicationUnit>(); foreach (var groupedAddress in groupedAddresses) { var area = groupedAddress.Key; //初始地址 double initNum = -1; //上一个地址 double preNum = -1; //上一个地址类型 Type preType = null; //记录一个地址组合当中的所有原始地址 var originalAddresses = new List <AddressUnit>(); //对组合内地址从小到大进行排序 var orderedAddresses = groupedAddress.OrderBy( address => AddressHelper.GetProtocalCoordinate(address.Address, address.SubAddress, AddressTranslator.GetAreaByteLength(address.Area))); foreach (var address in orderedAddresses) { //第一次进入时直接压入地址 if (initNum < 0) { initNum = AddressHelper.GetProtocalCoordinate(address.Address, address.SubAddress, AddressTranslator.GetAreaByteLength(address.Area)); originalAddresses.Add(address); } else { //如果当前地址小于已经记录的地址域,表示这个地址的开始已经记录过了 if (AddressHelper.GetProtocalCoordinate(address.Address, address.SubAddress, AddressTranslator.GetAreaByteLength(address.Area)) < AddressHelper.GetProtocalCoordinateNextPosition(preNum, preType, AddressTranslator.GetAreaByteLength(address.Area))) { originalAddresses.Add(address); //如果当前地址的末尾被记录,表示地址被记录的地址域覆盖,这个地址没有记录的必要 if (AddressHelper.GetProtocalCoordinateNextPosition( AddressHelper.GetProtocalCoordinate(address.Address, address.SubAddress, AddressTranslator.GetAreaByteLength(address.Area)), address.DataType, AddressTranslator.GetAreaByteLength(address.Area)) <= AddressHelper.GetProtocalCoordinateNextPosition(preNum, preType, AddressTranslator.GetAreaByteLength(address.Area))) { continue; } } //如果当前地址大于记录的地址域的开头,则表示地址已经不连续了 else if (AddressHelper.GetProtocalCoordinate(address.Address, address.SubAddress, AddressTranslator.GetAreaByteLength(address.Area)) > AddressHelper.GetProtocalCoordinateNextPosition(preNum, preType, AddressTranslator.GetAreaByteLength(address.Area))) { //上一个地址域压入返回结果,并把当前记录的结果清空。 ans.Add(new CommunicationUnit { Area = area, Address = (int)Math.Floor(initNum), GetCount = (int) Math.Ceiling( AddressHelper.MapProtocalGetCountToAbstractByteCount( preNum - (int)Math.Floor(initNum), AddressTranslator.GetAreaByteLength(address.Area), BigEndianValueHelper.Instance.ByteLength[preType.FullName])), DataType = typeof(byte), OriginalAddresses = originalAddresses.ToList() }); initNum = address.Address; originalAddresses.Clear(); originalAddresses.Add(address); } else { //地址连续,压入当前记录的结果 originalAddresses.Add(address); } } //把当前地址变为上一个地址 preNum = AddressHelper.GetProtocalCoordinate(address.Address, address.SubAddress, AddressTranslator.GetAreaByteLength(address.Area)); preType = address.DataType; } //最后一个地址域压入返回结果 ans.Add(new CommunicationUnit { Area = area, Address = (int)Math.Floor(initNum), GetCount = (int) Math.Ceiling( AddressHelper.MapProtocalGetCountToAbstractByteCount( preNum - (int)Math.Floor(initNum), AddressTranslator.GetAreaByteLength(area), BigEndianValueHelper.Instance.ByteLength[preType.FullName])), DataType = typeof(byte), OriginalAddresses = originalAddresses.ToList() }); } return(ans); }
/// <summary> /// 读取数据 /// </summary> /// <returns>从设备读取的数据</returns> public async Task <Dictionary <string, ReturnUnit> > GetDatasAsync(MachineGetDataType getDataType) { try { var ans = new Dictionary <string, ReturnUnit>(); //检测并连接设备 if (!BaseUtility.IsConnected) { await BaseUtility.ConnectAsync(); } //如果无法连接,终止 if (!BaseUtility.IsConnected) { return(null); } //遍历每一个实际向设备获取数据的连续地址 foreach (var communicateAddress in CommunicateAddresses) { //获取数据 var datas = await BaseUtility.GetDatasAsync( AddressFormater.FormatAddress(communicateAddress.Area, communicateAddress.Address, communicateAddress.SubAddress), (int) Math.Ceiling(communicateAddress.GetCount * BigEndianValueHelper.Instance.ByteLength[ communicateAddress.DataType.FullName])); //如果没有数据,终止 if (datas == null || (datas.Length != 0 && datas.Length < (int) Math.Ceiling(communicateAddress.GetCount * BigEndianValueHelper.Instance.ByteLength[ communicateAddress.DataType.FullName]))) { return(null); } foreach (var address in communicateAddress.OriginalAddresses) { //字节坐标的位置 var localPos = AddressHelper.MapProtocalCoordinateToAbstractCoordinate(address.Address, communicateAddress.Address, AddressTranslator.GetAreaByteLength(communicateAddress.Area)) + address.SubAddress * 0.125; //字节坐标的主地址位置 var localMainPos = (int)localPos; //字节坐标的子地址位置 var localSubPos = (int)((localPos - localMainPos) * 8); //根据类型选择返回结果的键是通讯标识还是地址 string key; switch (getDataType) { case MachineGetDataType.CommunicationTag: { key = address.CommunicationTag; break; } case MachineGetDataType.Address: { key = AddressFormater.FormatAddress(address.Area, address.Address, address.SubAddress); break; } case MachineGetDataType.Name: { key = address.Name; break; } default: { key = address.CommunicationTag; break; } } //如果没有数据返回空 if (datas.Length == 0) { ans.Add(key, new ReturnUnit { PlcValue = null, UnitExtend = address.UnitExtend }); } else { //将获取的数据和对应的通讯标识对应 ans.Add(key, new ReturnUnit { PlcValue = Convert.ToDouble( ValueHelper.GetInstance(BaseUtility.Endian) .GetValue(datas, ref localMainPos, ref localSubPos, address.DataType)) * address.Zoom, UnitExtend = address.UnitExtend }); } } } //如果不保持连接,断开连接 if (!KeepConnect) { BaseUtility.Disconnect(); } //返回数据 if (ans.All(p => p.Value.PlcValue == null)) { ans = null; } ErrorCount = 0; return(ans); } catch (Exception e) { Console.WriteLine(ConnectionToken + " " + e.Message); ErrorCount++; if (ErrorCount >= _maxErrorCount) { Disconnect(); } return(null); } }
public override IEnumerable <CommunicationUnit> Combine(IEnumerable <AddressUnit> addresses) { var continusAddresses = base.Combine(addresses).ToList(); var addressesGaps = new List <CommunicationUnitGap>(); CommunicationUnit preCommunicationUnit = null; foreach (var continusAddress in continusAddresses) { if (preCommunicationUnit == null) { preCommunicationUnit = continusAddress; continue; } if (continusAddress.Area == preCommunicationUnit.Area) { //计算间隔 var gap = new CommunicationUnitGap { EndUnit = continusAddress, GapNumber = (int) Math.Ceiling(AddressHelper.MapProtocalCoordinateToAbstractCoordinate( continusAddress.Address, preCommunicationUnit.Address, AddressTranslator.GetAreaByteLength(continusAddress.Area)) - preCommunicationUnit.GetCount * BigEndianValueHelper.Instance.ByteLength[ preCommunicationUnit.DataType.FullName]) }; addressesGaps.Add(gap); } preCommunicationUnit = continusAddress; } //减去间隔 var orderedGaps = addressesGaps.OrderBy(p => p.GapNumber); var jumpNumberInner = JumpNumber; foreach (var orderedGap in orderedGaps) { jumpNumberInner -= orderedGap.GapNumber; if (jumpNumberInner < 0) { break; } var nowAddress = orderedGap.EndUnit; var index = continusAddresses.IndexOf(nowAddress); index--; var preAddress = continusAddresses[index]; continusAddresses.RemoveAt(index); continusAddresses.RemoveAt(index); //合并两个已有的地址段,变为一个新的地址段 var newAddress = new CommunicationUnit { Area = nowAddress.Area, Address = preAddress.Address, GetCount = (int) (preAddress.GetCount * BigEndianValueHelper.Instance.ByteLength[preAddress.DataType.FullName]) + orderedGap.GapNumber + (int) (nowAddress.GetCount * BigEndianValueHelper.Instance.ByteLength[nowAddress.DataType.FullName]), DataType = typeof(byte), OriginalAddresses = preAddress.OriginalAddresses.ToList().Union(nowAddress.OriginalAddresses) }; continusAddresses.Insert(index, newAddress); } return(continusAddresses); }