From 9d07328625ef923ab9b8c905092559163a6811a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=BD=97=E5=9C=A3?= Date: Thu, 1 Sep 2016 10:45:47 +0800 Subject: [PATCH] Modbus ASCII and Siemens PPI support (not test), ComConnector Remaintainence. --- .../Modbus.Net.Modbus.csproj | 2 + .../Modbus.Net.Modbus/ModbusAsciiProtocal.cs | 23 +++ .../ModbusAsciiProtocalLinker.cs | 33 ++++ .../Modbus.Net.Modbus/ModbusProtocal.cs | 10 +- .../ModbusProtocalLinkerBytesExtend.cs | 36 ++++- .../ModbusRtuProtocalLinker.cs | 8 +- Modbus.Net/Modbus.Net.Modbus/ModbusUtility.cs | 9 ++ .../Modbus.Net.Siemens.csproj | 2 + .../Modbus.Net.Siemens/SiemensPpiProtocal.cs | 70 ++++++++ .../SiemensPpiProtocalLinker.cs | 69 ++++++++ .../Modbus.Net.Siemens/SiemensProtocal.cs | 78 ++++++++- .../SiemensProtocalLinkerBytesExtend.cs | 26 +++ .../Modbus.Net.Siemens/SiemensUtility.cs | 9 +- Modbus.Net/Modbus.Net/AddressCombiner.cs | 26 +-- Modbus.Net/Modbus.Net/BaseMachine.cs | 5 + Modbus.Net/Modbus.Net/CRC16.cs | 102 ++++++++++++ Modbus.Net/Modbus.Net/ComConnector.cs | 151 ++++++++++-------- Modbus.Net/Modbus.Net/ComProtocalLinker.cs | 8 +- Modbus.Net/Modbus.Net/ValueHelper.cs | 6 +- Modbus.Net/NA200H.UI.WPF/MainWindow.xaml.cs | 35 ++-- 20 files changed, 587 insertions(+), 121 deletions(-) create mode 100644 Modbus.Net/Modbus.Net.Modbus/ModbusAsciiProtocal.cs create mode 100644 Modbus.Net/Modbus.Net.Modbus/ModbusAsciiProtocalLinker.cs create mode 100644 Modbus.Net/Modbus.Net.Siemens/SiemensPpiProtocal.cs create mode 100644 Modbus.Net/Modbus.Net.Siemens/SiemensPpiProtocalLinker.cs diff --git a/Modbus.Net/Modbus.Net.Modbus/Modbus.Net.Modbus.csproj b/Modbus.Net/Modbus.Net.Modbus/Modbus.Net.Modbus.csproj index 651dd01..7ec1381 100644 --- a/Modbus.Net/Modbus.Net.Modbus/Modbus.Net.Modbus.csproj +++ b/Modbus.Net/Modbus.Net.Modbus/Modbus.Net.Modbus.csproj @@ -43,6 +43,8 @@ + + diff --git a/Modbus.Net/Modbus.Net.Modbus/ModbusAsciiProtocal.cs b/Modbus.Net/Modbus.Net.Modbus/ModbusAsciiProtocal.cs new file mode 100644 index 0000000..efaaf45 --- /dev/null +++ b/Modbus.Net/Modbus.Net.Modbus/ModbusAsciiProtocal.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Modbus.Net.Modbus +{ + /// + /// Modbus/Rtu协议 + /// + public class ModbusAsciiProtocal : ModbusProtocal + { + public ModbusAsciiProtocal() : this(ConfigurationManager.COM) + { + } + + public ModbusAsciiProtocal(string com) + { + ProtocalLinker = new ModbusAsciiProtocalLinker(com); + } + } +} diff --git a/Modbus.Net/Modbus.Net.Modbus/ModbusAsciiProtocalLinker.cs b/Modbus.Net/Modbus.Net.Modbus/ModbusAsciiProtocalLinker.cs new file mode 100644 index 0000000..36c9068 --- /dev/null +++ b/Modbus.Net/Modbus.Net.Modbus/ModbusAsciiProtocalLinker.cs @@ -0,0 +1,33 @@ +using System; +using System.Collections.Generic; +using System.IO.Ports; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Modbus.Net.Modbus +{ + public class ModbusAsciiProtocalLinker : ComProtocalLinker + { + public override bool? CheckRight(byte[] content) + { + if (!base.CheckRight(content).Value) return false; + //CRC校验失败 + string contentString = Encoding.ASCII.GetString(content); + if (!Crc16.GetInstance().LrcEfficacy(contentString)) + { + throw new ModbusProtocalErrorException(501); + } + //Modbus协议错误 + if (byte.Parse(contentString.Substring(3, 2)) > 127) + { + throw new ModbusProtocalErrorException(byte.Parse(contentString.Substring(5, 2))); + } + return true; + } + + public ModbusAsciiProtocalLinker(string com) : base(com, 9600, Parity.None, StopBits.One, 8) + { + } + } +} diff --git a/Modbus.Net/Modbus.Net.Modbus/ModbusProtocal.cs b/Modbus.Net/Modbus.Net.Modbus/ModbusProtocal.cs index a6e7eca..feb792f 100644 --- a/Modbus.Net/Modbus.Net.Modbus/ModbusProtocal.cs +++ b/Modbus.Net/Modbus.Net.Modbus/ModbusProtocal.cs @@ -124,9 +124,10 @@ namespace Modbus.Net.Modbus var translateAddress = addressTranslator.AddressTranslate(startAddress, false); FunctionCode = (byte)translateAddress.Area; StartAddress = (ushort)translateAddress.Address; - WriteCount = (ushort)Math.Ceiling(writeValue.Length / 2.0); - WriteByteCount = 0; - WriteValue = writeValue; + var writeByteValue = BigEndianValueHelper.Instance.ObjectArrayToByteArray(writeValue); + WriteCount = (ushort)(writeByteValue.Length / 2); + WriteByteCount = (byte)writeByteValue.Length; + WriteValue = writeByteValue; } public byte BelongAddress { get; private set; } @@ -139,7 +140,7 @@ namespace Modbus.Net.Modbus public byte WriteByteCount { get; private set; } - public object[] WriteValue { get; private set; } + public byte[] WriteValue { get; private set; } } public class WriteDataModbusOutputStruct : OutputStruct @@ -172,7 +173,6 @@ namespace Modbus.Net.Modbus var r_message = (WriteDataModbusInputStruct)message; byte[] formattingBytes = Format(r_message.BelongAddress, r_message.FunctionCode, r_message.StartAddress, r_message.WriteCount, r_message.WriteByteCount, r_message.WriteValue); - formattingBytes[6] = (byte)(formattingBytes.Length - 7); return formattingBytes; } diff --git a/Modbus.Net/Modbus.Net.Modbus/ModbusProtocalLinkerBytesExtend.cs b/Modbus.Net/Modbus.Net.Modbus/ModbusProtocalLinkerBytesExtend.cs index 2ded053..9f0ea79 100644 --- a/Modbus.Net/Modbus.Net.Modbus/ModbusProtocalLinkerBytesExtend.cs +++ b/Modbus.Net/Modbus.Net.Modbus/ModbusProtocalLinkerBytesExtend.cs @@ -1,4 +1,6 @@ using System; +using System.Collections.Generic; +using System.Text; namespace Modbus.Net.Modbus { @@ -43,10 +45,42 @@ namespace Modbus.Net.Modbus public override byte[] BytesDecact(byte[] content) { - //Modbus/Rtu协议收缩,抛弃后面1个字节的内容 + //Modbus/Rtu协议收缩,抛弃后面2个字节的内容 byte[] newContent = new byte[content.Length - 2]; Array.Copy(content, 0, newContent, 0, newContent.Length); return newContent; } } + + public class ModbusAsciiProtocalLinkerBytesExtend : ProtocalLinkerBytesExtend + { + public override byte[] BytesExtend(byte[] content) + { + List newContent = new List(); + newContent.AddRange(Encoding.ASCII.GetBytes(":")); + foreach (var number in content) + { + newContent.AddRange(Encoding.ASCII.GetBytes(number.ToString())); + } + newContent.AddRange(Encoding.ASCII.GetBytes(Crc16.GetInstance().GetLRC(content))); + newContent.Add(0x0d); + newContent.Add(0x0a); + return newContent.ToArray(); + } + + public override byte[] BytesDecact(byte[] content) + { + List newContent = new List(); + string ans = Encoding.ASCII.GetString(content); + var index = ans.IndexOf(Environment.NewLine); + ans = ans.Substring(1, index - 1); + for (int i = 0; i < ans.Length; i += 2) + { + var number = byte.Parse(ans.Substring(i, 2)); + newContent.Add(number); + } + newContent.RemoveAt(newContent.Count-1); + return newContent.ToArray(); + } + } } diff --git a/Modbus.Net/Modbus.Net.Modbus/ModbusRtuProtocalLinker.cs b/Modbus.Net/Modbus.Net.Modbus/ModbusRtuProtocalLinker.cs index edd8347..be5353f 100644 --- a/Modbus.Net/Modbus.Net.Modbus/ModbusRtuProtocalLinker.cs +++ b/Modbus.Net/Modbus.Net.Modbus/ModbusRtuProtocalLinker.cs @@ -1,4 +1,6 @@ -namespace Modbus.Net.Modbus +using System.IO.Ports; + +namespace Modbus.Net.Modbus { class ModbusRtuProtocalLinker : ComProtocalLinker { @@ -18,9 +20,9 @@ return true; } - public ModbusRtuProtocalLinker(string com) : base(com) + public ModbusRtuProtocalLinker(string com) : base(com, 9600, Parity.None, StopBits.One, 8) { - + } } } diff --git a/Modbus.Net/Modbus.Net.Modbus/ModbusUtility.cs b/Modbus.Net/Modbus.Net.Modbus/ModbusUtility.cs index 65d7c94..fd52cea 100644 --- a/Modbus.Net/Modbus.Net.Modbus/ModbusUtility.cs +++ b/Modbus.Net/Modbus.Net.Modbus/ModbusUtility.cs @@ -16,6 +16,10 @@ namespace Modbus.Net.Modbus /// Tcp连接 /// Tcp = 1, + /// + /// Ascii连接 + /// + Ascii = 2, } public class ModbusUtility : BaseUtility @@ -74,6 +78,11 @@ namespace Modbus.Net.Modbus Wrapper = ConnectionString == null ? new ModbusTcpProtocal() : (ConnectionStringPort == null ? new ModbusTcpProtocal(ConnectionString) : new ModbusTcpProtocal(ConnectionStringIp,ConnectionStringPort.Value)); break; } + case ModbusType.Ascii: + { + Wrapper = ConnectionString == null ? new ModbusAsciiProtocal() : new ModbusAsciiProtocal(ConnectionString); + break; + } } } } diff --git a/Modbus.Net/Modbus.Net.Siemens/Modbus.Net.Siemens.csproj b/Modbus.Net/Modbus.Net.Siemens/Modbus.Net.Siemens.csproj index c14b2d3..92c43e7 100644 --- a/Modbus.Net/Modbus.Net.Siemens/Modbus.Net.Siemens.csproj +++ b/Modbus.Net/Modbus.Net.Siemens/Modbus.Net.Siemens.csproj @@ -45,6 +45,8 @@ + + diff --git a/Modbus.Net/Modbus.Net.Siemens/SiemensPpiProtocal.cs b/Modbus.Net/Modbus.Net.Siemens/SiemensPpiProtocal.cs new file mode 100644 index 0000000..1620861 --- /dev/null +++ b/Modbus.Net/Modbus.Net.Siemens/SiemensPpiProtocal.cs @@ -0,0 +1,70 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Modbus.Net.Siemens +{ + public class SiemensPpiProtocal : SiemensProtocal + { + private readonly string _com; + private int _connectTryCount; + + public SiemensPpiProtocal() : this( ConfigurationManager.COM) + { + } + + public SiemensPpiProtocal(string com) + { + _com = com; + _connectTryCount = 0; + } + + public override byte[] SendReceive(bool isLittleEndian, params object[] content) + { + return AsyncHelper.RunSync(() => SendReceiveAsync(isLittleEndian, content)); + } + + public override async Task SendReceiveAsync(bool isLittleEndian, params object[] content) + { + if (ProtocalLinker == null || !ProtocalLinker.IsConnected) + { + await ConnectAsync(); + } + return await base.SendReceiveAsync(isLittleEndian, content); + } + + private async Task ForceSendReceiveAsync(ProtocalUnit unit, InputStruct content) + { + return await base.SendReceiveAsync(unit, content); + } + + public override bool Connect() + { + return AsyncHelper.RunSync(ConnectAsync); + } + + public override async Task ConnectAsync() + { + ProtocalLinker = new SiemensPpiProtocalLinker(_com); + var inputStruct = new ComCreateReferenceSiemensInputStruct(); + var outputStruct = + await await + ForceSendReceiveAsync(this[typeof (ComCreateReferenceSiemensProtocal)], + inputStruct). + ContinueWith(async answer => + { + if (!ProtocalLinker.IsConnected) return false; + var inputStruct2 = new ComEstablishAssociationSiemensInputStruct(); + var outputStruct2 = + (ComConfirmSiemensOutputStruct) + await + ForceSendReceiveAsync(this[typeof(ComEstablishAssociationSiemensProtocal)], + inputStruct2); + return outputStruct2 != null; + }); + return outputStruct != null; + } + } +} diff --git a/Modbus.Net/Modbus.Net.Siemens/SiemensPpiProtocalLinker.cs b/Modbus.Net/Modbus.Net.Siemens/SiemensPpiProtocalLinker.cs new file mode 100644 index 0000000..9f03be6 --- /dev/null +++ b/Modbus.Net/Modbus.Net.Siemens/SiemensPpiProtocalLinker.cs @@ -0,0 +1,69 @@ +using System; +using System.Collections.Generic; +using System.IO.Ports; +using System.Linq; +using System.Linq.Expressions; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +namespace Modbus.Net.Siemens +{ + public class SiemensPpiProtocalLinker : ComProtocalLinker + { + public override async Task SendReceiveAsync(byte[] content) + { + byte[] extBytes = BytesExtend(content); + if (extBytes[6] == 0x7c) + { + var inputStruct2 = new ComEstablishAssociationSiemensInputStruct(); + var receiveBytes2 = + await SendReceiveWithoutExtAndDecAsync( + new ComEstablishAssociationSiemensProtocal().Format(inputStruct2)); + } + var receiveBytes = await SendReceiveWithoutExtAndDecAsync(extBytes); + while (receiveBytes.Length == 1 && receiveBytes[0] == 0xf9) + { + Thread.Sleep(500); + var inputStruct2 = new ComEstablishAssociationSiemensInputStruct(); + receiveBytes = + await SendReceiveWithoutExtAndDecAsync( + new ComEstablishAssociationSiemensProtocal().Format(inputStruct2)); + } + if (content.Length > 6 && receiveBytes.Length == 1 && receiveBytes[0] == 0xe5) + { + var inputStruct2 = new ComEstablishAssociationSiemensInputStruct(); + var receiveBytes2 = + await SendReceiveWithoutExtAndDecAsync( + new ComEstablishAssociationSiemensProtocal().Format(inputStruct2)); + return BytesDecact(receiveBytes2); + } + return BytesDecact(receiveBytes); + } + + public override bool? CheckRight(byte[] content) + { + if (!base.CheckRight(content).Value) return false; + int fcsCheck = 0; + if (content.Length == 1 && content[0] == 0xe5) + { + return true; + } + if (content.Length == 6 && content[3] == 0) return true; + for (int i = 4; i < content.Length - 2; i++) + { + fcsCheck += content[i]; + } + fcsCheck = fcsCheck%256; + if (fcsCheck != content[content.Length - 2]) return false; + if (content[content.Length - 1] != 0x16) return false; + if (content[1] != content.Length - 6) return false; + return true; + } + + public SiemensPpiProtocalLinker(string com) + : base(com, 9600, Parity.Even, StopBits.One, 8) + { + } + } +} diff --git a/Modbus.Net/Modbus.Net.Siemens/SiemensProtocal.cs b/Modbus.Net/Modbus.Net.Siemens/SiemensProtocal.cs index da8a4d6..aa0f716 100644 --- a/Modbus.Net/Modbus.Net.Siemens/SiemensProtocal.cs +++ b/Modbus.Net/Modbus.Net.Siemens/SiemensProtocal.cs @@ -37,6 +37,30 @@ namespace Modbus.Net.Siemens } + internal class ComCreateReferenceSiemensInputStruct : InputStruct + { + + } + + internal class ComCreateReferenceSiemensOutputStruct : OutputStruct + { + + } + + internal class ComCreateReferenceSiemensProtocal : SpecialProtocalUnit + { + public override byte[] Format(InputStruct message) + { + var r_message = (ComCreateReferenceSiemensInputStruct) message; + return Format((byte)0x10, (byte)0x02, (byte)0x00, (byte)0x49, (byte)0x4B, (byte)0x16); + } + + public override OutputStruct Unformat(byte[] messageBytes, ref int pos) + { + return new ComCreateReferenceSiemensOutputStruct(); + } + } + internal class CreateReferenceSiemensInputStruct : InputStruct { public CreateReferenceSiemensInputStruct(byte tdpuSize, ushort srcTsap, ushort dstTsap) @@ -119,6 +143,38 @@ namespace Modbus.Net.Siemens } } + internal class ComEstablishAssociationSiemensInputStruct : InputStruct + { + } + + internal class ComConfirmSiemensOutputStruct : OutputStruct + { + public ComConfirmSiemensOutputStruct(byte confirmByte) + { + ConfirmByte = confirmByte; + } + + public byte ConfirmByte { get; set; } + } + + internal class ComEstablishAssociationSiemensProtocal : SpecialProtocalUnit + { + public override byte[] Format(InputStruct message) + { + var r_message = (ComEstablishAssociationSiemensInputStruct)message; + return Format((byte)0x10, (byte)0x02, (byte)0x00, (byte)0x5c, (byte)0x5e, (byte)0x16); + } + + public override OutputStruct Unformat(byte[] messageBytes, ref int pos) + { + //if (messageBytes.Length == 1) + //{ + var confirmByte = BigEndianValueHelper.Instance.GetByte(messageBytes, ref pos); + return new ComConfirmSiemensOutputStruct(confirmByte); + //} + } + } + internal class EstablishAssociationSiemensInputStruct : InputStruct { public EstablishAssociationSiemensInputStruct(ushort pduRef, ushort maxCalling, ushort maxCalled, ushort maxPdu) @@ -245,7 +301,7 @@ namespace Modbus.Net.Siemens byte area = r_message.Area; int offsetBit = r_message.Offset*8; byte[] offsetBitBytes = BigEndianValueHelper.Instance.GetBytes(offsetBit); - return Format(new byte[7], protoId, rosctr, redId, pduRef, parLg, datLg, serviceId, numberOfVariables + return Format(new byte[6], (byte)0x6c, protoId, rosctr, redId, pduRef, parLg, datLg, serviceId, numberOfVariables , variableSpec, vAddrLg, syntaxId, type, numberOfElements, dbBlock, area, offsetBitBytes.Skip(1).ToArray()); } @@ -325,18 +381,26 @@ namespace Modbus.Net.Siemens 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 + return Format(new byte[6], (byte)0x7c, protoId, rosctr, redId, pduRef, parLg, datLg, serviceId, numberOfVariables , variableSpec, vAddrLg, syntaxId, typeR, numberOfElements, dbBlock, area, offsetBitBytes.Skip(1).ToArray(), reserved, type, numberOfWriteBits, valueBytes); } 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); + if (messageBytes.Length == 1) + { + byte accessResult = BigEndianValueHelper.Instance.GetByte(messageBytes, ref pos); + return new WriteRequestSiemensOutputStruct(0, accessResult == 0xe5 ? SiemensAccessResult.NoError : SiemensAccessResult.InvalidAddress); + } + else + { + 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); + } } } diff --git a/Modbus.Net/Modbus.Net.Siemens/SiemensProtocalLinkerBytesExtend.cs b/Modbus.Net/Modbus.Net.Siemens/SiemensProtocalLinkerBytesExtend.cs index de72afc..80698b4 100644 --- a/Modbus.Net/Modbus.Net.Siemens/SiemensProtocalLinkerBytesExtend.cs +++ b/Modbus.Net/Modbus.Net.Siemens/SiemensProtocalLinkerBytesExtend.cs @@ -18,4 +18,30 @@ namespace Modbus.Net.Siemens return newContent; } } + + public class SiemensPpiProtocalLinkerBytesExtend : ProtocalLinkerBytesExtend + { + public override byte[] BytesExtend(byte[] content) + { + byte[] newContent = new byte[content.Length + 2]; + Array.Copy(content, 0, newContent, 0, content.Length); + Array.Copy(new byte[] { 0x68, (byte)(content.Length - 4), (byte)(content.Length - 4), 0x68, 0x02, 0x00 }, 0, newContent, 0, 6); + int check = 0; + for (int i = 4; i < newContent.Length - 2; i++) + { + check += newContent[i]; + } + check = check%256; + newContent[newContent.Length - 2] = (byte) check; + newContent[newContent.Length - 1] = 0x16; + return newContent; + } + + public override byte[] BytesDecact(byte[] content) + { + byte[] newContent = new byte[content.Length - 9]; + Array.Copy(content, 7, newContent, 0, newContent.Length); + return newContent; + } + } } diff --git a/Modbus.Net/Modbus.Net.Siemens/SiemensUtility.cs b/Modbus.Net/Modbus.Net.Siemens/SiemensUtility.cs index 3f739c7..61057d8 100644 --- a/Modbus.Net/Modbus.Net.Siemens/SiemensUtility.cs +++ b/Modbus.Net/Modbus.Net.Siemens/SiemensUtility.cs @@ -73,10 +73,11 @@ namespace Modbus.Net.Siemens _siemensType = value; switch (_siemensType) { - //case SiemensType.Ppi: - // { - // throw new NotImplementedException(); - // } + case SiemensType.Ppi: + { + Wrapper = ConnectionString == null ? new SiemensPpiProtocal() : new SiemensPpiProtocal(ConnectionString); + break; + } //case SiemensType.Mpi: // { // throw new NotImplementedException(); diff --git a/Modbus.Net/Modbus.Net/AddressCombiner.cs b/Modbus.Net/Modbus.Net/AddressCombiner.cs index fb9fc0e..0014fb5 100644 --- a/Modbus.Net/Modbus.Net/AddressCombiner.cs +++ b/Modbus.Net/Modbus.Net/AddressCombiner.cs @@ -38,8 +38,6 @@ namespace Modbus.Net double initNum = -1; double preNum = -1; Type preType = null; - double getCount = 0; - double byteCount = 0; List originalAddresses = new List(); var orderedAddresses = groupedAddress.OrderBy( @@ -51,8 +49,6 @@ namespace Modbus.Net if (initNum < 0) { initNum = address.Address + address.SubAddress * (0.125 / AddressTranslator.GetAreaByteLength(address.Area)); - getCount = BigEndianValueHelper.Instance.ByteLength[address.DataType.FullName] / AddressTranslator.GetAreaByteLength(address.Area); - byteCount = BigEndianValueHelper.Instance.ByteLength[address.DataType.FullName]; originalAddresses.Add(address); } else @@ -63,7 +59,17 @@ namespace Modbus.Net BigEndianValueHelper.Instance.ByteLength[preType.FullName]/ AddressTranslator.GetAreaByteLength(address.Area)) { - continue; + originalAddresses.Add(address); + if (address.Address + + address.SubAddress*(0.125/AddressTranslator.GetAreaByteLength(address.Area)) + + BigEndianValueHelper.Instance.ByteLength[address.DataType.FullName]/ + AddressTranslator.GetAreaByteLength(address.Area) <= + preNum + + BigEndianValueHelper.Instance.ByteLength[preType.FullName]/ + AddressTranslator.GetAreaByteLength(address.Area)) + { + continue; + } } else if (address.Address + address.SubAddress*(0.125/AddressTranslator.GetAreaByteLength(address.Area)) > @@ -75,22 +81,16 @@ namespace Modbus.Net { Area = area, Address = (int) Math.Floor(initNum), - GetCount = (int)Math.Ceiling(((int)Math.Floor(preNum) - (int)Math.Floor(initNum) + 1) * AddressTranslator.GetAreaByteLength(address.Area)), + GetCount = (int)Math.Ceiling(((int)Math.Floor(preNum) - (int)Math.Floor(initNum)) * AddressTranslator.GetAreaByteLength(address.Area) + BigEndianValueHelper.Instance.ByteLength[preType.FullName]), DataType = typeof (byte), OriginalAddresses = originalAddresses.ToList(), }); initNum = address.Address; - getCount = BigEndianValueHelper.Instance.ByteLength[address.DataType.FullName]/ - AddressTranslator.GetAreaByteLength(address.Area); - byteCount = BigEndianValueHelper.Instance.ByteLength[address.DataType.FullName]; originalAddresses.Clear(); originalAddresses.Add(address); } else { - getCount += BigEndianValueHelper.Instance.ByteLength[address.DataType.FullName]/ - AddressTranslator.GetAreaByteLength(address.Area); - byteCount += BigEndianValueHelper.Instance.ByteLength[address.DataType.FullName]; originalAddresses.Add(address); } } @@ -101,7 +101,7 @@ namespace Modbus.Net { Area = area, Address = (int)Math.Floor(initNum), - GetCount = (int)Math.Ceiling(((int)Math.Floor(preNum) - (int)Math.Floor(initNum) + 1) * AddressTranslator.GetAreaByteLength(area)), + GetCount = (int)Math.Ceiling(((int)Math.Floor(preNum) - (int)Math.Floor(initNum)) * AddressTranslator.GetAreaByteLength(area) + BigEndianValueHelper.Instance.ByteLength[preType.FullName]), DataType = typeof (byte), OriginalAddresses = originalAddresses.ToList() }); diff --git a/Modbus.Net/Modbus.Net/BaseMachine.cs b/Modbus.Net/Modbus.Net/BaseMachine.cs index ad942a4..aba5f85 100644 --- a/Modbus.Net/Modbus.Net/BaseMachine.cs +++ b/Modbus.Net/Modbus.Net/BaseMachine.cs @@ -405,6 +405,11 @@ namespace Modbus.Net valueHelper.ByteArrayToObjectArray(datas, new KeyValuePair(typeof (byte), datas.Length))); } + //如果不保持连接,断开连接 + if (!KeepConnect) + { + BaseUtility.Disconnect(); + } } catch (Exception e) { diff --git a/Modbus.Net/Modbus.Net/CRC16.cs b/Modbus.Net/Modbus.Net/CRC16.cs index 3947647..1ef6e21 100644 --- a/Modbus.Net/Modbus.Net/CRC16.cs +++ b/Modbus.Net/Modbus.Net/CRC16.cs @@ -26,6 +26,7 @@ namespace Modbus.Net /// 生成CRC码 /// /// 发送或返回的命令,CRC码除外 + /// 存储CRC码的字节的数组 /// 生成的CRC码 public short GetCRC(byte[] message, ref byte[] Rcvbuf) { @@ -84,5 +85,106 @@ namespace Modbus.Net } #endregion + + /// + /// 取模FF(255) + /// 取反+1 + /// + /// + /// + public bool LrcEfficacy(string message) + { + var index = message.IndexOf(Environment.NewLine, StringComparison.InvariantCulture); + var writeUncheck = message.Substring(1, index - 3); + var checkString = message.Substring(index - 3, 2); + char[] hexArray = new char[writeUncheck.Length]; + hexArray = writeUncheck.ToCharArray(); + int decNum = 0, decNumMSB = 0, decNumLSB = 0; + int decByte, decByteTotal = 0; + + bool msb = true; + + for (int t = 0; t <= hexArray.GetUpperBound(0); t++) + { + if ((hexArray[t] >= 48) && (hexArray[t] <= 57)) + + decNum = (hexArray[t] - 48); + + else if ((hexArray[t] >= 65) & (hexArray[t] <= 70)) + decNum = 10 + (hexArray[t] - 65); + + if (msb) + { + decNumMSB = decNum * 16; + msb = false; + } + else + { + decNumLSB = decNum; + msb = true; + } + if (msb) + { + decByte = decNumMSB + decNumLSB; + decByteTotal += decByte; + } + } + + decByteTotal = (255 - decByteTotal) + 1; + decByteTotal = decByteTotal & 255; + + int a, b = 0; + + string hexByte = "", hexTotal = ""; + double i; + + for (i = 0; decByteTotal > 0; i++) + { + //b = Convert.ToInt32(System.Math.Pow(16.0, i)); + a = decByteTotal % 16; + decByteTotal /= 16; + if (a <= 9) + hexByte = a.ToString(); + else + { + switch (a) + { + case 10: + hexByte = "A"; + break; + case 11: + hexByte = "B"; + break; + case 12: + hexByte = "C"; + break; + case 13: + hexByte = "D"; + break; + case 14: + hexByte = "E"; + break; + case 15: + hexByte = "F"; + break; + } + } + hexTotal = String.Concat(hexByte, hexTotal); + } + return hexTotal == checkString; + } + + public string GetLRC(byte[] code) + { + int sum = 0; + foreach (byte b in code) + { + sum += b; + } + sum = sum % 255;//取模FF(255) + sum = ~sum + 1;//取反+1 + string lrc = Convert.ToString(sum, 16); + return lrc; + } } } diff --git a/Modbus.Net/Modbus.Net/ComConnector.cs b/Modbus.Net/Modbus.Net/ComConnector.cs index 6881f08..125eeff 100644 --- a/Modbus.Net/Modbus.Net/ComConnector.cs +++ b/Modbus.Net/Modbus.Net/ComConnector.cs @@ -8,28 +8,50 @@ namespace Modbus.Net { public class ComConnector : BaseConnector, IDisposable { - public override string ConnectionToken { get { return _com; } - } + public override string ConnectionToken => _com; private SerialPort _serialPort1; + private SerialPort SerialPort1 + { + get + { + if (_serialPort1 == null) + { + _serialPort1 = new SerialPort + { + PortName = _com, + BaudRate = _baudRate, + Parity = _parity, + StopBits = _stopBits, + DataBits = _dataBits, + ReadTimeout = _timeoutTime, + }; + } + return _serialPort1; + } + + } + public delegate byte[] GetDate(byte[] bts); //private GetDate mygetDate; private readonly string _com; + private readonly int _timeoutTime; + private readonly int _baudRate; + private readonly Parity _parity; + private readonly StopBits _stopBits; + private readonly int _dataBits; - public ComConnector(string com, int timeoutTime) + public ComConnector(string com, int baudRate, Parity parity, StopBits stopBits, int dataBits, int timeoutTime) { - this._com = com; - _serialPort1 = new SerialPort - { - PortName = com, - BaudRate = 9600, - Parity = Parity.None, - StopBits = StopBits.One, - DataBits = 8, - ReadTimeout = timeoutTime, - }; + _com = com; + _timeoutTime = timeoutTime; + _baudRate = baudRate; + _parity = parity; + _stopBits = stopBits; + _dataBits = dataBits; + //端口号 //比特率 //奇偶校验 @@ -41,24 +63,20 @@ namespace Modbus.Net public override bool IsConnected { - get { return _serialPort1 != null && _serialPort1.IsOpen; } + get { return SerialPort1 != null && SerialPort1.IsOpen; } } public override bool Connect() { - if (_serialPort1 != null) + try { - try - { - _serialPort1.Open(); - return true; - } - catch - { - return false; - } + SerialPort1.Open(); + return true; + } + catch + { + return false; } - return false; } public override Task ConnectAsync() @@ -68,11 +86,11 @@ namespace Modbus.Net public override bool Disconnect() { - if (_serialPort1 != null) + if (SerialPort1 != null) { try { - _serialPort1.Close(); + Dispose(); return true; } catch @@ -100,16 +118,24 @@ namespace Modbus.Net { try { - if (!_serialPort1.IsOpen) + if (!SerialPort1.IsOpen) { - _serialPort1.Open(); + try + { + SerialPort1.Open(); + } + catch (Exception) + { + Dispose(); + SerialPort1.Open(); + } } - _serialPort1.Write(sendbytes, 0, sendbytes.Length); + SerialPort1.Write(sendbytes, 0, sendbytes.Length); return ReadMsg(); } catch { - _serialPort1.Close(); + Dispose(); return null; } } @@ -123,7 +149,7 @@ namespace Modbus.Net { try { - _serialPort1.Write(sendbytes, 0, sendbytes.Length); + SerialPort1.Write(sendbytes, 0, sendbytes.Length); return true; } catch (Exception) @@ -148,22 +174,21 @@ namespace Modbus.Net { try { - if (!_serialPort1.IsOpen) + if (!SerialPort1.IsOpen) { - _serialPort1.Open(); + SerialPort1.Open(); } - byte[] data = new byte[200]; + byte[] data; Thread.Sleep(100); - int i = _serialPort1.Read(data, 0, _serialPort1.BytesToRead); + int i = ReadComm(out data, 10, 5000, 1000); byte[] returndata = new byte[i]; Array.Copy(data, 0, returndata, 0, i); - _serialPort1.Close(); return returndata; } - catch (Exception) + catch (Exception ex) { - _serialPort1.Close(); + Dispose(); return null; } } @@ -181,33 +206,35 @@ namespace Modbus.Net public int ReadComm(out Byte[] readBuf, int bufRoom, int HowTime, int ByteTime) { //throw new System.NotImplementedException(); - readBuf = new Byte[64]; + readBuf = new Byte[1023]; Array.Clear(readBuf, 0, readBuf.Length); int nReadLen, nBytelen; - if (_serialPort1.IsOpen == false) + if (SerialPort1.IsOpen == false) return -1; nBytelen = 0; - _serialPort1.ReadTimeout = HowTime; + SerialPort1.ReadTimeout = HowTime; try { - readBuf[nBytelen] = (byte) _serialPort1.ReadByte(); - byte[] bTmp = new byte[1023]; - Array.Clear(bTmp, 0, bTmp.Length); - - nReadLen = ReadBlock(out bTmp, bufRoom - 1, ByteTime); - - if (nReadLen > 0) + while (SerialPort1.BytesToRead > 0) { - Array.Copy(bTmp, 0, readBuf, 1, nReadLen); - nBytelen = 1 + nReadLen; + readBuf[nBytelen] = (byte) SerialPort1.ReadByte(); + byte[] bTmp = new byte[bufRoom]; + Array.Clear(bTmp, 0, bTmp.Length); + nReadLen = ReadBlock(bTmp, bufRoom, ByteTime); + + if (nReadLen > 0) + { + Array.Copy(bTmp, 0, readBuf, nBytelen + 1, nReadLen); + nBytelen += 1 + nReadLen; + } + + else if (nReadLen == 0) + nBytelen += 1; } - - else if (nReadLen == 0) - nBytelen = 1; } catch (Exception ex) { @@ -225,25 +252,21 @@ namespace Modbus.Net /// 串口数据缓冲空间大小 /// 字节间隔最大时间 /// 从串口实际读入的字节个数 - public int ReadBlock(out byte[] ReadBuf, int ReadRoom, int ByteTime) + public int ReadBlock(byte[] ReadBuf, int ReadRoom, int ByteTime) { - //throw new System.NotImplementedException(); - ReadBuf = new byte[1024]; - Array.Clear(ReadBuf, 0, ReadBuf.Length); - sbyte nBytelen; //long nByteRead; - if (_serialPort1.IsOpen == false) + if (SerialPort1.IsOpen == false) return 0; nBytelen = 0; - _serialPort1.ReadTimeout = ByteTime; + SerialPort1.ReadTimeout = ByteTime; - while (nBytelen < (ReadRoom - 1)) + while (nBytelen < ReadRoom - 1 && SerialPort1.BytesToRead > 0) { try { - ReadBuf[nBytelen] = (byte) _serialPort1.ReadByte(); + ReadBuf[nBytelen] = (byte) SerialPort1.ReadByte(); nBytelen++; // add one } catch (Exception ex) @@ -253,7 +276,6 @@ namespace Modbus.Net } ReadBuf[nBytelen] = 0x00; return nBytelen; - } @@ -342,6 +364,7 @@ namespace Modbus.Net { _serialPort1.Close(); _serialPort1.Dispose(); + _serialPort1 = null; } } } diff --git a/Modbus.Net/Modbus.Net/ComProtocalLinker.cs b/Modbus.Net/Modbus.Net/ComProtocalLinker.cs index 10abe66..f3195ea 100644 --- a/Modbus.Net/Modbus.Net/ComProtocalLinker.cs +++ b/Modbus.Net/Modbus.Net/ComProtocalLinker.cs @@ -1,18 +1,18 @@ using System; +using System.IO.Ports; namespace Modbus.Net { public abstract class ComProtocalLinker : ProtocalLinker { - protected ComProtocalLinker() : this(ConfigurationManager.COM) + protected ComProtocalLinker(int baudRate, Parity parity, StopBits stopBits, int dataBits) : this(ConfigurationManager.COM, baudRate, parity, stopBits, dataBits) { - } - protected ComProtocalLinker(string com) + protected ComProtocalLinker(string com, int baudRate, Parity parity, StopBits stopBits, int dataBits) { //初始化连对象 - _baseConnector = new ComConnector(com, 30000); + _baseConnector = new ComConnector(com, baudRate, parity, stopBits, dataBits, 30000); } } } diff --git a/Modbus.Net/Modbus.Net/ValueHelper.cs b/Modbus.Net/Modbus.Net/ValueHelper.cs index 6c45751..b0381a5 100644 --- a/Modbus.Net/Modbus.Net/ValueHelper.cs +++ b/Modbus.Net/Modbus.Net/ValueHelper.cs @@ -416,12 +416,12 @@ namespace Modbus.Net { if (subPos < 0 && subPos >= 8) throw new IndexOutOfRangeException(); int ans = number % 2; - int i = 7; - while (i >= subPos) + int i = 0; + while (i <= subPos) { ans = number % 2; number /= 2; - i--; + i++; } subPos += 1; if (subPos > 7) diff --git a/Modbus.Net/NA200H.UI.WPF/MainWindow.xaml.cs b/Modbus.Net/NA200H.UI.WPF/MainWindow.xaml.cs index 2e8fbb4..6f54cf1 100644 --- a/Modbus.Net/NA200H.UI.WPF/MainWindow.xaml.cs +++ b/Modbus.Net/NA200H.UI.WPF/MainWindow.xaml.cs @@ -41,25 +41,26 @@ namespace NA200H.UI.WPF private void GetMachineEnter() { - machine = new ModbusMachine(ModbusType.Tcp, "192.168.3.12", new List() + //machine = new ModbusMachine(ModbusType.Tcp, "192.168.3.12", new List() + //{ + //new AddressUnit() {Id = "1", Area = "MW", Address = 1, CommunicationTag = "Add1", DataType = typeof(ushort), Zoom = 1, DecimalPos = 0}, + //new AddressUnit() {Id = "2", Area = "MW", Address = 2, CommunicationTag = "Add2", DataType = typeof(ushort), Zoom = 1, DecimalPos = 0}, + //new AddressUnit() {Id = "3", Area = "MW", Address = 3, CommunicationTag = "Add3", DataType = typeof(ushort), Zoom = 1, DecimalPos = 0}, + //new AddressUnit() {Id = "4", Area = "MW", Address = 4, CommunicationTag = "Ans", DataType = typeof(ushort), Zoom = 1, DecimalPos = 0}, + //}); + //machine.AddressFormater = new AddressFormaterNA200H(); + //machine.AddressTranslator = new AddressTranslatorNA200H(); + //machine.AddressCombiner = new AddressCombinerContinus(machine.AddressTranslator); + //machine.AddressCombinerSet = new AddressCombinerContinus(machine.AddressTranslator); + machine = new SiemensMachine(SiemensType.Ppi, "COM4", SiemensMachineModel.S7_300, new List() { - new AddressUnit() {Id = "1", Area = "MW", Address = 1, CommunicationTag = "Add1", DataType = typeof(ushort), Zoom = 1, DecimalPos = 0}, - new AddressUnit() {Id = "2", Area = "MW", Address = 2, CommunicationTag = "Add2", DataType = typeof(ushort), Zoom = 1, DecimalPos = 0}, - new AddressUnit() {Id = "3", Area = "MW", Address = 3, CommunicationTag = "Add3", DataType = typeof(ushort), Zoom = 1, DecimalPos = 0}, - new AddressUnit() {Id = "4", Area = "MW", Address = 4, CommunicationTag = "Ans", DataType = typeof(ushort), Zoom = 1, DecimalPos = 0}, + new AddressUnit() {Id = "1", Area = "V", Address = 0, CommunicationTag = "Add1", DataType = typeof(ushort), Zoom = 1, DecimalPos = 0}, + new AddressUnit() {Id = "2", Area = "V", Address = 2, CommunicationTag = "Add2", DataType = typeof(ushort), Zoom = 1, DecimalPos = 0}, + new AddressUnit() {Id = "3", Area = "V", Address = 4, CommunicationTag = "Add3", DataType = typeof(ushort), Zoom = 1, DecimalPos = 0}, + new AddressUnit() {Id = "4", Area = "V", Address = 6, CommunicationTag = "Ans", DataType = typeof(ushort), Zoom = 1, DecimalPos = 0} }); - machine.AddressFormater = new AddressFormaterNA200H(); - machine.AddressTranslator = new AddressTranslatorNA200H(); machine.AddressCombiner = new AddressCombinerContinus(machine.AddressTranslator); machine.AddressCombinerSet = new AddressCombinerContinus(machine.AddressTranslator); - //machine = new SiemensMachine(SiemensType.Tcp, "192.168.3.11:102", SiemensMachineModel.S7_300, new List() - //{ - //new AddressUnit() {Id = "1", Area = "V", Address = 0, CommunicationTag = "Add1", DataType = typeof(ushort), Zoom = 1, DecimalPos = 0}, - //new AddressUnit() {Id = "2", Area = "V", Address = 2, CommunicationTag = "Add2", DataType = typeof(ushort), Zoom = 1, DecimalPos = 0}, - //new AddressUnit() {Id = "3", Area = "V", Address = 4, CommunicationTag = "Add3", DataType = typeof(ushort), Zoom = 1, DecimalPos = 0}, - //new AddressUnit() {Id = "4", Area = "V", Address = 6, CommunicationTag = "Ans", DataType = typeof(ushort), Zoom = 1, DecimalPos = 0} - //}); - //machine.AddressCombiner = new AddressCombinerContinus(); var result = machine.GetDatas(MachineGetDataType.CommunicationTag); var resultFormat = BaseMachine.MapGetValuesToSetValues(result); SetValue(new ushort[4] {(ushort)resultFormat["Add1"], (ushort)resultFormat["Add2"], (ushort)resultFormat["Add3"], (ushort)resultFormat["Ans"]}); @@ -85,8 +86,8 @@ namespace NA200H.UI.WPF ushort.TryParse(Add1.Text, out add1); ushort.TryParse(Add2.Text, out add2); ushort.TryParse(Add3.Text, out add3); - utility.SetDatas(0x02, 0x00, "NW 1", new object[] { add1, add2, add3 }); - //utility.SetDatas(0x02, 0x00, "V 1", new object[] { add1, add2, add3 }); + //utility.SetDatas(0x02, 0x00, "NW 1", new object[] { add1, add2, add3 }); + utility.SetDatas(0x02, 0x00, "V 1", new object[] { add1, add2, add3 }); Thread.Sleep(100); GetUtilityEnter(); }