From e09eeadd80ce9e4ddd10fecef37ef3be9fb7a8e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=BD=97=E5=9C=A3?= Date: Tue, 30 Aug 2016 17:34:20 +0800 Subject: [PATCH] SetBit Support (not test) --- .../Modbus.Net.Modbus/ModbusProtocal.cs | 2 +- .../ModbusRtuProtocalLinker.cs | 4 +- .../ModbusTcpProtocalLinker.cs | 4 +- Modbus.Net/Modbus.Net.Modbus/ModbusUtility.cs | 11 +- Modbus.Net/Modbus.Net.OPC/OpcDaConnector.cs | 56 ++++++- .../Modbus.Net.OPC/OpcDaProtocalLinker.cs | 4 +- Modbus.Net/Modbus.Net.OPC/OpcDaUtility.cs | 28 ++-- Modbus.Net/Modbus.Net.OPC/OpcProtocal.cs | 76 +++------ .../SiemensTcpProtocalLinker.cs | 4 +- .../Modbus.Net.Siemens/SiemensUtility.cs | 11 +- Modbus.Net/Modbus.Net/AddressCombiner.cs | 11 +- Modbus.Net/Modbus.Net/BaseMachine.cs | 153 ++++++++++-------- Modbus.Net/Modbus.Net/BaseUtility.cs | 27 ++-- Modbus.Net/Modbus.Net/ProtocalLinker.cs | 7 +- Modbus.Net/Modbus.Net/ValueHelper.cs | 139 ++++++++++++++-- 15 files changed, 343 insertions(+), 194 deletions(-) diff --git a/Modbus.Net/Modbus.Net.Modbus/ModbusProtocal.cs b/Modbus.Net/Modbus.Net.Modbus/ModbusProtocal.cs index ca303be..a6e7eca 100644 --- a/Modbus.Net/Modbus.Net.Modbus/ModbusProtocal.cs +++ b/Modbus.Net/Modbus.Net.Modbus/ModbusProtocal.cs @@ -124,7 +124,7 @@ namespace Modbus.Net.Modbus var translateAddress = addressTranslator.AddressTranslate(startAddress, false); FunctionCode = (byte)translateAddress.Area; StartAddress = (ushort)translateAddress.Address; - WriteCount = (ushort)writeValue.Length; + WriteCount = (ushort)Math.Ceiling(writeValue.Length / 2.0); WriteByteCount = 0; WriteValue = writeValue; } diff --git a/Modbus.Net/Modbus.Net.Modbus/ModbusRtuProtocalLinker.cs b/Modbus.Net/Modbus.Net.Modbus/ModbusRtuProtocalLinker.cs index 86e31ec..edd8347 100644 --- a/Modbus.Net/Modbus.Net.Modbus/ModbusRtuProtocalLinker.cs +++ b/Modbus.Net/Modbus.Net.Modbus/ModbusRtuProtocalLinker.cs @@ -2,9 +2,9 @@ { class ModbusRtuProtocalLinker : ComProtocalLinker { - public override bool CheckRight(byte[] content) + public override bool? CheckRight(byte[] content) { - if (!base.CheckRight(content)) return false; + if (!base.CheckRight(content).Value) return false; //CRC校验失败 if (!Crc16.GetInstance().CrcEfficacy(content)) { diff --git a/Modbus.Net/Modbus.Net.Modbus/ModbusTcpProtocalLinker.cs b/Modbus.Net/Modbus.Net.Modbus/ModbusTcpProtocalLinker.cs index e6a67f3..85dff06 100644 --- a/Modbus.Net/Modbus.Net.Modbus/ModbusTcpProtocalLinker.cs +++ b/Modbus.Net/Modbus.Net.Modbus/ModbusTcpProtocalLinker.cs @@ -2,9 +2,9 @@ { public class ModbusTcpProtocalLinker : TcpProtocalLinker { - public override bool CheckRight(byte[] content) + public override bool? CheckRight(byte[] content) { - if (!base.CheckRight(content)) return false; + if (!base.CheckRight(content).Value) return false; //长度校验失败 if (content[5] != content.Length - 6) { diff --git a/Modbus.Net/Modbus.Net.Modbus/ModbusUtility.cs b/Modbus.Net/Modbus.Net.Modbus/ModbusUtility.cs index bba0f34..65d7c94 100644 --- a/Modbus.Net/Modbus.Net.Modbus/ModbusUtility.cs +++ b/Modbus.Net/Modbus.Net.Modbus/ModbusUtility.cs @@ -22,6 +22,9 @@ namespace Modbus.Net.Modbus { private ModbusType _modbusType; + public override bool GetLittleEndian => Wrapper[typeof (ReadDataModbusProtocal)].IsLittleEndian; + public override bool SetLittleEndian => Wrapper[typeof (WriteDataModbusProtocal)].IsLittleEndian; + protected string ConnectionStringIp { get @@ -94,7 +97,7 @@ namespace Modbus.Net.Modbus ModbusType = (ModbusType) connectionType; } - public override async Task GetDatasAsync(byte belongAddress, byte masterAddress, string startAddress, int getByteCount) + public override async Task GetDatasAsync(byte belongAddress, byte masterAddress, string startAddress, int getByteCount) { try { @@ -103,11 +106,7 @@ namespace Modbus.Net.Modbus var outputStruct = await Wrapper.SendReceiveAsync(Wrapper[typeof (ReadDataModbusProtocal)], inputStruct) as ReadDataModbusOutputStruct; - return new GetDataReturnDef() - { - ReturnValue = outputStruct?.DataValue, - IsLittleEndian = Wrapper[typeof(ReadDataModbusProtocal)].IsLittleEndian, - }; + return outputStruct?.DataValue; } catch { diff --git a/Modbus.Net/Modbus.Net.OPC/OpcDaConnector.cs b/Modbus.Net/Modbus.Net.OPC/OpcDaConnector.cs index 3756e83..36057ed 100644 --- a/Modbus.Net/Modbus.Net.OPC/OpcDaConnector.cs +++ b/Modbus.Net/Modbus.Net.OPC/OpcDaConnector.cs @@ -95,15 +95,58 @@ namespace Modbus.Net.OPC { try { - string tag = Encoding.UTF8.GetString(message); - var result = await _daClient.ReadAsync(tag); - if (result.QualityGood) + var pos = 0; + var protocal = BigEndianValueHelper.Instance.GetByte(message, ref pos); + if (protocal == 0) { - return BigEndianValueHelper.Instance.GetBytes(result.Value, result.Value.GetType()); + byte[] tagBytes = new byte[message.Length - 1]; + Array.Copy(message, 1, tagBytes, 0, tagBytes.Length); + string tag = Encoding.UTF8.GetString(tagBytes); + var result = await _daClient.ReadAsync(tag); + if (result.QualityGood) + { + return BigEndianValueHelper.Instance.GetBytes(result.Value, result.Value.GetType()); + } + else + { + return Encoding.ASCII.GetBytes("NoData"); + } } else { - return Encoding.ASCII.GetBytes("NoData"); + int index = 0; + for (int i = 1; i < message.Length - 3; i++) + { + if (message[i] == 0x00 && message[i + 1] == 0xff && message[i + 2] == 0xff && + message[i + 3] == 0x00) + { + index = i; + break; + } + } + + int index2 = 0; + for (int i = index + 4; i < message.Length - 3; i++) + { + if (message[i] == 0x00 && message[i + 1] == 0xff && message[i + 2] == 0xff && + message[i + 3] == 0x00) + { + index = i; + break; + } + } + byte[] tagBytes = new byte[index - 1]; + Array.Copy(message, 1, tagBytes, 0, tagBytes.Length); + string tag = Encoding.UTF8.GetString(tagBytes); + byte[] typeBytes = new byte[index2 - index - 4]; + Array.Copy(message, index + 4, typeBytes, 0, typeBytes.Length); + Type type = Type.GetType(Encoding.UTF8.GetString(typeBytes)); + byte[] valueBytes = new byte[message.Length - index2 - 4]; + Array.Copy(message, index2 + 4, valueBytes, 0, valueBytes.Length); + int mainpos = 0, subpos = 0; + object value = BigEndianValueHelper.Instance.GetValue(valueBytes, ref mainpos, ref subpos, type); + await _daClient.WriteAsync(tag, value); + return new byte[] {1}; } } catch (Exception e) @@ -111,8 +154,7 @@ namespace Modbus.Net.OPC //AddInfo("opc client exception:" + e); return Encoding.ASCII.GetBytes("NoData"); //return null; - } - + } } private void AddInfo(string message) diff --git a/Modbus.Net/Modbus.Net.OPC/OpcDaProtocalLinker.cs b/Modbus.Net/Modbus.Net.OPC/OpcDaProtocalLinker.cs index 595187a..c3933b0 100644 --- a/Modbus.Net/Modbus.Net.OPC/OpcDaProtocalLinker.cs +++ b/Modbus.Net/Modbus.Net.OPC/OpcDaProtocalLinker.cs @@ -18,11 +18,11 @@ namespace Modbus.Net.OPC _baseConnector = OpcDaConnector.Instance(host); } - public override bool CheckRight(byte[] content) + public override bool? CheckRight(byte[] content) { if (content != null && content.Length == 6 && Encoding.ASCII.GetString(content) == "NoData") { - return false; + return null; } return base.CheckRight(content); } diff --git a/Modbus.Net/Modbus.Net.OPC/OpcDaUtility.cs b/Modbus.Net/Modbus.Net.OPC/OpcDaUtility.cs index ca3d84b..335efdc 100644 --- a/Modbus.Net/Modbus.Net.OPC/OpcDaUtility.cs +++ b/Modbus.Net/Modbus.Net.OPC/OpcDaUtility.cs @@ -8,6 +8,9 @@ namespace Modbus.Net.OPC { public class OpcDaUtility : BaseUtility { + public override bool GetLittleEndian => Wrapper[typeof (ReadRequestOpcProtocal)].IsLittleEndian; + public override bool SetLittleEndian => Wrapper[typeof (WriteRequestOpcProtocal)].IsLittleEndian; + public OpcDaUtility(string connectionString) { ConnectionString = connectionString; @@ -19,19 +22,15 @@ namespace Modbus.Net.OPC { } - public override async Task GetDatasAsync(byte belongAddress, byte masterAddress, string startAddress, int getByteCount) + public override async Task GetDatasAsync(byte belongAddress, byte masterAddress, string startAddress, int getByteCount) { try { - var readRequestOpcInputStruct = new ReadRequestOpcInputStruct(startAddress, getByteCount); + var readRequestOpcInputStruct = new ReadRequestOpcInputStruct(startAddress); var readRequestOpcOutputStruct = await Wrapper.SendReceiveAsync(Wrapper[typeof(ReadRequestOpcProtocal)], readRequestOpcInputStruct) as ReadRequestOpcOutputStruct; - return new GetDataReturnDef() - { - ReturnValue = readRequestOpcOutputStruct?.GetValue, - IsLittleEndian = Wrapper[typeof (ReadRequestOpcProtocal)].IsLittleEndian - }; + return readRequestOpcOutputStruct?.GetValue; } catch (Exception) { @@ -39,9 +38,20 @@ namespace Modbus.Net.OPC } } - public override Task SetDatasAsync(byte belongAddress, byte masterAddress, string startAddress, object[] setContents) + public override async Task SetDatasAsync(byte belongAddress, byte masterAddress, string startAddress, object[] setContents) { - throw new NotImplementedException(); + try + { + var writeRequestOpcInputStruct = new WriteRequestOpcInputStruct(startAddress, setContents[0]); + var writeRequestOpcOutputStruct = + await + Wrapper.SendReceiveAsync(Wrapper[typeof(WriteRequestOpcProtocal)], writeRequestOpcInputStruct) as WriteRequestOpcOutputStruct; + return writeRequestOpcOutputStruct?.WriteResult == true; + } + catch (Exception) + { + return false; + } } } } diff --git a/Modbus.Net/Modbus.Net.OPC/OpcProtocal.cs b/Modbus.Net/Modbus.Net.OPC/OpcProtocal.cs index b18d720..16c6a03 100644 --- a/Modbus.Net/Modbus.Net.OPC/OpcProtocal.cs +++ b/Modbus.Net/Modbus.Net.OPC/OpcProtocal.cs @@ -13,14 +13,12 @@ namespace Modbus.Net.OPC public class ReadRequestOpcInputStruct : InputStruct { - public ReadRequestOpcInputStruct(string tag, int getCount) + public ReadRequestOpcInputStruct(string tag) { Tag = tag; - GetCount = getCount; } public string Tag { get; private set; } - public int GetCount { get; private set; } } public class ReadRequestOpcOutputStruct : OutputStruct @@ -38,7 +36,7 @@ namespace Modbus.Net.OPC public override byte[] Format(InputStruct message) { var r_message = (ReadRequestOpcInputStruct) message; - return Format(Encoding.UTF8.GetBytes(r_message.Tag)); + return Format((byte)0x00, Encoding.UTF8.GetBytes(r_message.Tag)); } public override OutputStruct Unformat(byte[] messageBytes, ref int pos) @@ -47,77 +45,43 @@ namespace Modbus.Net.OPC } } - /*public class WriteRequestSiemensInputStruct : InputStruct + public class WriteRequestOpcInputStruct : InputStruct { - public WriteRequestSiemensInputStruct(ushort pduRef, string startAddress, object[] writeValue, AddressTranslator addressTranslator) + public WriteRequestOpcInputStruct(string tag, object setValue) { - PduRef = pduRef; - var address = addressTranslator.AddressTranslate(startAddress, true); - Offset = address.Key; - int area = address.Value; - Area = (byte)(area % 256); - DbBlock = Area == 0x84 ? (ushort)(area / 256) : (ushort)0; - WriteValue = writeValue; + Tag = tag; + SetValue = setValue; } - public ushort PduRef { get; private set; } - public ushort DbBlock { get; private set; } - public byte Area { get; private set; } - public int Offset { get; private set; } - public object[] WriteValue { get; private set; } + public string Tag { get; private set; } + public object SetValue { get; private set; } } - public class WriteRequestSiemensOutputStruct : OutputStruct + public class WriteRequestOpcOutputStruct : OutputStruct { - public WriteRequestSiemensOutputStruct(ushort pduRef, SiemensAccessResult accessResult) + public WriteRequestOpcOutputStruct(bool writeResult) { - PduRef = pduRef; - AccessResult = accessResult; + WriteResult = writeResult; } - public ushort PduRef { get; private set; } - public SiemensAccessResult AccessResult { get; private set; } + public bool WriteResult { get; private set; } } - public class WriteRequestSiemensProtocal : ProtocalUnit + public class WriteRequestOpcProtocal : ProtocalUnit { public override byte[] Format(InputStruct message) { - var r_message = (WriteRequestSiemensInputStruct)message; - byte[] valueBytes = BigEndianValueHelper.Instance.ObjectArrayToByteArray(r_message.WriteValue); - const byte protoId = 0x32; - const byte rosctr = 0x01; - const ushort redId = 0x0000; - ushort pduRef = r_message.PduRef; - const ushort parLg = 14; // 参数字节数(2+12的倍数),目前仅为14 - ushort datLg = (ushort)(4 + valueBytes.Length); // 数据字节数 - const byte serviceId = 0x05; - const byte numberOfVariables = 1; - const byte variableSpec = 0x12; - const byte vAddrLg = 0x0A; - const byte syntaxId = 0x10; - const byte typeR = (byte)SiemensTypeCode.Byte; - ushort numberOfElements = (ushort)valueBytes.Length; - ushort dbBlock = r_message.DbBlock; - byte area = r_message.Area; - int offsetBit = r_message.Offset * 8; - byte[] offsetBitBytes = BigEndianValueHelper.Instance.GetBytes(offsetBit); - const byte reserved = 0x00; - const byte type = (byte)SiemensDataType.OtherAccess; - ushort numberOfWriteBits = (ushort)(valueBytes.Length * 8); - return Format(new byte[7], protoId, rosctr, redId, pduRef, parLg, datLg, serviceId, numberOfVariables - , variableSpec, vAddrLg, syntaxId, typeR, numberOfElements, dbBlock, area, - offsetBitBytes.Skip(1).ToArray(), reserved, type, numberOfWriteBits, valueBytes); + var r_message = (WriteRequestOpcInputStruct)message; + byte[] tag = Encoding.UTF8.GetBytes(r_message.Tag); + return Format((byte)0x00, tag, (int)0x00ffff00, r_message.SetValue.GetType().FullName, (int)0x00ffff00, r_message.SetValue); } public override OutputStruct Unformat(byte[] messageBytes, ref int pos) { - pos = 4; - ushort pduRef = BigEndianValueHelper.Instance.GetUShort(messageBytes, ref pos); - pos = 14; - byte accessResult = BigEndianValueHelper.Instance.GetByte(messageBytes, ref pos); - return new WriteRequestSiemensOutputStruct(pduRef, (SiemensAccessResult)accessResult); + var ansByte = BigEndianValueHelper.Instance.GetByte(messageBytes, ref pos); + var ans = ansByte != 0; + return new WriteRequestOpcOutputStruct(ans); } - }*/ + } } diff --git a/Modbus.Net/Modbus.Net.Siemens/SiemensTcpProtocalLinker.cs b/Modbus.Net/Modbus.Net.Siemens/SiemensTcpProtocalLinker.cs index 36ca1b3..8d5dbfa 100644 --- a/Modbus.Net/Modbus.Net.Siemens/SiemensTcpProtocalLinker.cs +++ b/Modbus.Net/Modbus.Net.Siemens/SiemensTcpProtocalLinker.cs @@ -4,9 +4,9 @@ namespace Modbus.Net.Siemens { public class SiemensTcpProtocalLinker : TcpProtocalLinker { - public override bool CheckRight(byte[] content) + public override bool? CheckRight(byte[] content) { - if (!base.CheckRight(content)) return false; + if (!base.CheckRight(content).Value) return false; switch (content[5]) { case 0xd0: diff --git a/Modbus.Net/Modbus.Net.Siemens/SiemensUtility.cs b/Modbus.Net/Modbus.Net.Siemens/SiemensUtility.cs index 73d6360..3f739c7 100644 --- a/Modbus.Net/Modbus.Net.Siemens/SiemensUtility.cs +++ b/Modbus.Net/Modbus.Net.Siemens/SiemensUtility.cs @@ -30,6 +30,9 @@ namespace Modbus.Net.Siemens private readonly ushort _maxCalled; private readonly ushort _maxPdu; + public override bool GetLittleEndian => Wrapper[typeof (ReadRequestSiemensProtocal)].IsLittleEndian; + public override bool SetLittleEndian => Wrapper[typeof (WriteRequestSiemensProtocal)].IsLittleEndian; + protected string ConnectionStringIp { get @@ -148,7 +151,7 @@ namespace Modbus.Net.Siemens ConnectionType = (SiemensType) connectionType; } - public override async Task GetDatasAsync(byte belongAddress, byte materAddress, string startAddress, int getByteCount) + public override async Task GetDatasAsync(byte belongAddress, byte materAddress, string startAddress, int getByteCount) { try { @@ -157,11 +160,7 @@ namespace Modbus.Net.Siemens await Wrapper.SendReceiveAsync(Wrapper[typeof (ReadRequestSiemensProtocal)], readRequestSiemensInputStruct) as ReadRequestSiemensOutputStruct; - return new GetDataReturnDef() - { - ReturnValue = readRequestSiemensOutputStruct?.GetValue, - IsLittleEndian = Wrapper[typeof (ReadRequestSiemensProtocal)].IsLittleEndian - }; + return readRequestSiemensOutputStruct?.GetValue; } catch (Exception) { diff --git a/Modbus.Net/Modbus.Net/AddressCombiner.cs b/Modbus.Net/Modbus.Net/AddressCombiner.cs index 89e8cfd..fb9fc0e 100644 --- a/Modbus.Net/Modbus.Net/AddressCombiner.cs +++ b/Modbus.Net/Modbus.Net/AddressCombiner.cs @@ -41,7 +41,12 @@ namespace Modbus.Net double getCount = 0; double byteCount = 0; List originalAddresses = new List(); - foreach (var address in groupedAddress.OrderBy(address => address.Address + address.SubAddress * (0.125 / AddressTranslator.GetAreaByteLength(address.Area)))) + var orderedAddresses = + groupedAddress.OrderBy( + address => + address.Address + + address.SubAddress*(0.125/AddressTranslator.GetAreaByteLength(address.Area))); + foreach (var address in orderedAddresses) { if (initNum < 0) { @@ -70,7 +75,7 @@ namespace Modbus.Net { Area = area, Address = (int) Math.Floor(initNum), - GetCount = (int) Math.Ceiling(byteCount), + GetCount = (int)Math.Ceiling(((int)Math.Floor(preNum) - (int)Math.Floor(initNum) + 1) * AddressTranslator.GetAreaByteLength(address.Area)), DataType = typeof (byte), OriginalAddresses = originalAddresses.ToList(), }); @@ -96,7 +101,7 @@ namespace Modbus.Net { Area = area, Address = (int)Math.Floor(initNum), - GetCount = (int)Math.Ceiling(byteCount), + GetCount = (int)Math.Ceiling(((int)Math.Floor(preNum) - (int)Math.Floor(initNum) + 1) * AddressTranslator.GetAreaByteLength(area)), DataType = typeof (byte), OriginalAddresses = originalAddresses.ToList() }); diff --git a/Modbus.Net/Modbus.Net/BaseMachine.cs b/Modbus.Net/Modbus.Net/BaseMachine.cs index cd970bf..ad942a4 100644 --- a/Modbus.Net/Modbus.Net/BaseMachine.cs +++ b/Modbus.Net/Modbus.Net/BaseMachine.cs @@ -144,7 +144,7 @@ namespace Modbus.Net /// 读取数据 /// /// 从设备读取的数据 - public async Task> GetDatasAsync(MachineGetDataType getDataType) + public async Task> GetDatasAsync(MachineGetDataType getDataType) { try { @@ -160,7 +160,7 @@ namespace Modbus.Net foreach (var communicateAddress in CommunicateAddresses) { //获取数据 - var datasReturn = + var datas = await BaseUtility.GetDatasAsync(2, 0, AddressFormater.FormatAddress(communicateAddress.Area, communicateAddress.Address, 0), @@ -169,30 +169,21 @@ namespace Modbus.Net BigEndianValueHelper.Instance.ByteLength[ communicateAddress.DataType.FullName])); - byte[] datas; - //如果设备本身能获取到数据但是没有数据 - if (datasReturn == null) - { - datas = null; - } - else - { - datas = datasReturn.ReturnValue; + //如果没有数据,终止 + if (datas == null || (datas.Length != 0 && datas.Length < + (int) + Math.Ceiling(communicateAddress.GetCount* + BigEndianValueHelper.Instance.ByteLength[ + communicateAddress.DataType.FullName]))) + return null; - //如果没有数据,终止 - 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 = (address.Address - communicateAddress.Address)* - AddressTranslator.GetAreaByteLength(communicateAddress.Area)+address.SubAddress/8.0; + AddressTranslator.GetAreaByteLength(communicateAddress.Area) + + address.SubAddress/8.0; var localMainPos = (int) localPos; var localSubPos = (int) ((localPos - localMainPos)*8); @@ -200,23 +191,23 @@ namespace Modbus.Net switch (getDataType) { case MachineGetDataType.CommunicationTag: - { - key = address.CommunicationTag; - break; - } + { + key = address.CommunicationTag; + break; + } case MachineGetDataType.Address: - { - key = AddressFormater.FormatAddress(address.Area, address.Address, address.SubAddress); - break; - } + { + key = AddressFormater.FormatAddress(address.Area, address.Address, address.SubAddress); + break; + } default: - { - key = address.CommunicationTag; - break; - } + { + key = address.CommunicationTag; + break; + } } - if (datas == null) + if (datas.Length == 0) { ans.Add(key, new ReturnUnit { @@ -232,11 +223,13 @@ namespace Modbus.Net { PlcValue = Convert.ToDouble( - datasReturn.IsLittleEndian - ? ValueHelper.Instance.GetValue(datas, ref localMainPos, ref localSubPos, address.DataType) + BaseUtility.GetLittleEndian + ? ValueHelper.Instance.GetValue(datas, ref localMainPos, ref localSubPos, + address.DataType) .ToString() - : BigEndianValueHelper.Instance.GetValue(datas, ref localMainPos, ref localSubPos, - address.DataType)) * address.Zoom, + : BigEndianValueHelper.Instance.GetValue(datas, ref localMainPos, + ref localSubPos, + address.DataType))*address.Zoom, UnitExtend = address.UnitExtend }); } @@ -297,13 +290,17 @@ namespace Modbus.Net foreach (var value in values) { //根据设置类型找到对应的地址描述 - AddressUnit address = null; + 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)); + 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: @@ -324,42 +321,57 @@ namespace Modbus.Net } addresses.Add(address); } - //将地址编码成与实际设备通讯的地址,注意这个地址必须是连续的 + //将地址编码成与实际设备通讯的地址 var communcationUnits = AddressCombinerSet.Combine(addresses); //遍历每条通讯的连续地址 foreach (var communicateAddress in communcationUnits) { - List datasList = new List(); - //需要设置的字节数,计数 - var setCount = - communicateAddress.GetCount* - BigEndianValueHelper.Instance.ByteLength[communicateAddress.DataType.FullName]; - //总数 - var allBytes = setCount; //编码开始地址 var addressStart = AddressFormater.FormatAddress(communicateAddress.Area, - communicateAddress.Address); - - while (setCount > 0) + communicateAddress.Address); + + var datasReturn = await BaseUtility.GetDatasAsync(2, 0, + AddressFormater.FormatAddress(communicateAddress.Area, communicateAddress.Address, 0), + (int) + Math.Ceiling(communicateAddress.GetCount* + BigEndianValueHelper.Instance.ByteLength[ + communicateAddress.DataType.FullName])); + + var valueHelper = BaseUtility.SetLittleEndian + ? ValueHelper.Instance + : BigEndianValueHelper.Instance; + //如果设备本身能获取到数据但是没有数据 + 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 localPos = (allBytes - setCount) / AddressTranslator.GetAreaByteLength(communicateAddress.Area); + var byteCount = (addressUnit.Address - communicateAddress.Address + + addressUnit.SubAddress*0.125/ + AddressTranslator.GetAreaByteLength(communicateAddress.Area)) * + AddressTranslator.GetAreaByteLength(communicateAddress.Area); + 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 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 addressUnit = - GetAddresses.SingleOrDefault( - p => - p.Area == communicateAddress.Area && - p.Address == communicateAddress.Address + (int) localPos && - p.SubAddress == subPos); - //如果没有相应地址,跳过 - if (addressUnit == null) continue; //获取写入类型 Type dataType = addressUnit.DataType; switch (setDataType) @@ -367,22 +379,31 @@ namespace Modbus.Net case MachineSetDataType.Address: { //获取要写入的值 - var value = values.SingleOrDefault(p => p.Key == address || (address2 != null && p.Key == address2)); + var value = + values.SingleOrDefault( + p => p.Key == address || (address2 != null && p.Key == address2)); //将要写入的值加入队列 - datasList.Add(Convert.ChangeType(value.Value / addressUnit.Zoom, dataType)); + 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); - datasList.Add(Convert.ChangeType(value.Value / addressUnit.Zoom, dataType)); + var data = Convert.ChangeType(value.Value/addressUnit.Zoom, dataType); + if (!valueHelper.SetValue(datas, mainByteCount, localByteCount, data)) + return false; break; } } - setCount -= BigEndianValueHelper.Instance.ByteLength[dataType.FullName]; } //写入数据 - await BaseUtility.SetDatasAsync(2, 0, addressStart, datasList.ToArray()); + await + BaseUtility.SetDatasAsync(2, 0, addressStart, + valueHelper.ByteArrayToObjectArray(datas, + new KeyValuePair(typeof (byte), datas.Length))); } } catch (Exception e) diff --git a/Modbus.Net/Modbus.Net/BaseUtility.cs b/Modbus.Net/Modbus.Net/BaseUtility.cs index eb8b883..6709271 100644 --- a/Modbus.Net/Modbus.Net/BaseUtility.cs +++ b/Modbus.Net/Modbus.Net/BaseUtility.cs @@ -5,12 +5,6 @@ using System.Threading.Tasks; namespace Modbus.Net { - public class GetDataReturnDef - { - public byte[] ReturnValue { get; set; } - public bool IsLittleEndian { get; set; } - } - public abstract class BaseUtility { /// @@ -19,6 +13,15 @@ namespace Modbus.Net protected BaseProtocal Wrapper; protected string ConnectionString { get; set; } + /// + /// 获取协议是否遵循小端格式 + /// + public abstract bool GetLittleEndian { get; } + /// + /// 设置协议是否遵循小端格式 + /// + public abstract bool SetLittleEndian { get; } + /// /// 设备是否已经连接 /// @@ -56,7 +59,7 @@ namespace Modbus.Net /// 开始地址 /// 获取字节数个数 /// 接收到的byte数据 - public virtual GetDataReturnDef GetDatas(byte belongAddress, byte masterAddress, string startAddress, int getByteCount) + public virtual byte[] GetDatas(byte belongAddress, byte masterAddress, string startAddress, int getByteCount) { return AsyncHelper.RunSync(() => GetDatasAsync(belongAddress, masterAddress, startAddress, getByteCount)); } @@ -69,7 +72,7 @@ namespace Modbus.Net /// 开始地址 /// 获取字节数个数 /// 接收到的byte数据 - public abstract Task GetDatasAsync(byte belongAddress, byte masterAddress, string startAddress, int getByteCount); + public abstract Task GetDatasAsync(byte belongAddress, byte masterAddress, string startAddress, int getByteCount); /// /// 获取数据 @@ -102,8 +105,8 @@ namespace Modbus.Net double bCount = BigEndianValueHelper.Instance.ByteLength[typeName]; var getReturnValue = await GetDatasAsync(belongAddress, masterAddress, startAddress, (int)Math.Ceiling(bCount * getTypeAndCount.Value)); - var getBytes = getReturnValue.ReturnValue; - return getReturnValue.IsLittleEndian + var getBytes = getReturnValue; + return GetLittleEndian ? ValueHelper.Instance.ByteArrayToObjectArray(getBytes, getTypeAndCount) : BigEndianValueHelper.Instance.ByteArrayToObjectArray(getBytes, getTypeAndCount); } @@ -187,8 +190,8 @@ namespace Modbus.Net let bCount = BigEndianValueHelper.Instance.ByteLength[typeName] select (int) Math.Ceiling(bCount*getTypeAndCount.Value)).Sum(); var getReturnValue = await GetDatasAsync(belongAddress, masterAddress, startAddress, bAllCount); - byte[] getBytes = getReturnValue.ReturnValue; - return getReturnValue.IsLittleEndian + byte[] getBytes = getReturnValue; + return GetLittleEndian ? ValueHelper.Instance.ByteArrayToObjectArray(getBytes, translateTypeAndCount) : BigEndianValueHelper.Instance.ByteArrayToObjectArray(getBytes, translateTypeAndCount); } diff --git a/Modbus.Net/Modbus.Net/ProtocalLinker.cs b/Modbus.Net/Modbus.Net/ProtocalLinker.cs index 4d07b4d..04dc728 100644 --- a/Modbus.Net/Modbus.Net/ProtocalLinker.cs +++ b/Modbus.Net/Modbus.Net/ProtocalLinker.cs @@ -64,7 +64,7 @@ namespace Modbus.Net { byte[] extBytes = BytesExtend(content); byte[] receiveBytes = await SendReceiveWithoutExtAndDecAsync(extBytes); - return receiveBytes == null ? null : BytesDecact(receiveBytes); + return receiveBytes == null ? null : receiveBytes.Length == 0 ? receiveBytes : BytesDecact(receiveBytes); } /// @@ -87,7 +87,8 @@ namespace Modbus.Net //发送数据 byte[] receiveBytes = await _baseConnector.SendMsgAsync(content); //容错处理 - return !CheckRight(receiveBytes) ? null : receiveBytes; + var checkRight = CheckRight(receiveBytes); + return checkRight == null ? new byte[0] : (!checkRight.Value ? null : receiveBytes); //返回字符 } @@ -96,7 +97,7 @@ namespace Modbus.Net /// /// 接收协议的内容 /// 协议是否是正确的 - public virtual bool CheckRight(byte[] content) + public virtual bool? CheckRight(byte[] content) { if (content != null) return true; Disconnect(); diff --git a/Modbus.Net/Modbus.Net/ValueHelper.cs b/Modbus.Net/Modbus.Net/ValueHelper.cs index 88b5316..b1e55db 100644 --- a/Modbus.Net/Modbus.Net/ValueHelper.cs +++ b/Modbus.Net/Modbus.Net/ValueHelper.cs @@ -259,7 +259,7 @@ namespace Modbus.Net } case "System.Boolean": { - bool value = Instance.GetBit(data, ref pos, ref subPos); + bool value = _Instance.GetBit(data, ref pos, ref subPos); return value; } default: @@ -413,8 +413,8 @@ namespace Modbus.Net /// 小数位 /// 对应位置的bit元素 public bool GetBit(byte number, ref int pos, ref int subPos) - { - if (subPos < 0 && subPos > 8) throw new IndexOutOfRangeException(); + { + if (subPos < 0 && subPos >= 8) throw new IndexOutOfRangeException(); int ans = number % 2; int i = 7; while (i >= subPos) @@ -424,7 +424,7 @@ namespace Modbus.Net i--; } subPos += 1; - if (subPos >= 8) + if (subPos < 0) { pos++; subPos = 0; @@ -697,6 +697,90 @@ namespace Modbus.Net return array; } + public bool SetValue(byte[] contents, int setPos, int subPos, object setValue) + { + var type = setValue.GetType(); + + switch (type.FullName) + { + case "System.Int16": + { + bool success = _Instance.SetValue(contents, setPos, (short)setValue); + return success; + } + case "System.Int32": + { + bool success = _Instance.SetValue(contents, setPos, (int) setValue); + return success; + } + case "System.Int64": + { + bool success = _Instance.SetValue(contents, setPos, (long) setValue); + return success; + } + case "System.UInt16": + { + bool success = _Instance.SetValue(contents, setPos, (ushort) setValue); + return success; + } + case "System.UInt32": + { + bool success = _Instance.SetValue(contents, setPos, (uint) setValue); + return success; + } + case "System.UInt64": + { + bool success = _Instance.SetValue(contents, setPos, (ulong) setValue); + return success; + } + case "System.Single": + { + bool success = _Instance.SetValue(contents, setPos, (float) setValue); + return success; + } + case "System.Double": + { + bool success = _Instance.SetValue(contents, setPos, (double) setValue); + return success; + } + case "System.Byte": + { + bool success = _Instance.SetValue(contents, setPos, (byte) setValue); + return success; + } + case "System.Boolean": + { + bool success = _Instance.SetBit(contents, setPos, subPos, (bool) setValue); + return success; + } + default: + { + throw new NotImplementedException("没有实现除整数以外的其它转换方式"); + } + } + } + + /// + /// 将short值设置到byte数组中 + /// + /// 待设置的byte数组 + /// 设置的位置 + /// 要设置的值 + /// + public virtual bool SetValue(byte[] contents, int pos, object setValue) + { + try + { + byte[] datas = _Instance.GetBytes(setValue, setValue.GetType()); + Array.Copy(datas, 0, contents, pos, datas.Length); + return true; + } + catch (Exception) + { + return false; + } + } + /// /// 设置对应数字中相应位置的bit的值 /// @@ -709,28 +793,43 @@ namespace Modbus.Net int creation = 0; if (setBit) { - for (int i = 0; i < 8; i++) + for (int i = 7; i >= 0; i--) { creation *= 2; if (i == subPos) creation++; } - return (byte) (number | creation); + return (byte)(number | creation); } else { - for (int i = 0; i < 8; i++) + for (int i = 7; i >= 0; i--) { creation *= 2; if (i != subPos) creation++; } - return (byte) (number & creation); + return (byte)(number & creation); } } - public virtual byte SetBit(byte[] number, int pos, int subPos, bool setBit) + /// + /// 设置一组数据中的一个bit + /// + /// 待设置的字节数组 + /// 位置 + /// bit位置 + /// bit数 + /// + public virtual bool SetBit(byte[] contents, int pos, int subPos, bool setValue) { - SetBit(number[pos], subPos, setBit); - return GetByte(number, ref pos); + try + { + contents[pos] = SetBit(contents[pos], subPos, setValue); + return true; + } + catch (Exception) + { + return false; + } } } @@ -855,9 +954,16 @@ namespace Modbus.Net public override bool GetBit(byte[] number, ref int pos, ref int subPos) { - var tpos = 7 - subPos; - var bit = base.GetBit(number[pos], ref pos, ref tpos); - subPos = tpos - 7; + if (subPos < 0 && subPos > 7) throw new IndexOutOfRangeException(); + var tspos = 7 - subPos; + var tpos = pos; + var bit = GetBit(number[pos], ref tpos, ref tspos); + subPos += 1; + if (subPos > 7) + { + pos++; + subPos = 0; + } return bit; } @@ -874,10 +980,9 @@ namespace Modbus.Net return t; } - public override byte SetBit(byte[] number, int pos, int subPos, bool setBit) + public override bool SetBit(byte[] number, int pos, int subPos, bool setBit) { - Array.Reverse(number); - return base.SetBit(number, pos, subPos, setBit); + return base.SetBit(number, pos, 7 - subPos, setBit); } private Byte[] Reverse(Byte[] data)