diff --git a/IoTClient.Tests/Modbus_Tests/ModBusRtuClient_tests.cs b/IoTClient.Tests/Modbus_Tests/ModBusRtuClient_tests.cs index e462315..c6e9041 100644 --- a/IoTClient.Tests/Modbus_Tests/ModBusRtuClient_tests.cs +++ b/IoTClient.Tests/Modbus_Tests/ModBusRtuClient_tests.cs @@ -14,7 +14,7 @@ namespace IoTClient.Tests.Modbus byte stationNumber = 1;//站号 public ModbusRtuClient_tests() { - client = new ModbusRtuClient("COM3", 9600, 8, StopBits.One, Parity.None); + client = new ModbusRtuClient("COM2", 9600, 8, StopBits.One, Parity.None); } [Fact] diff --git a/IoTClient.Tests/Modbus_Tests/ModBusTcpClient_tests.cs b/IoTClient.Tests/Modbus_Tests/ModBusTcpClient_tests.cs index 58e94b0..a69c484 100644 --- a/IoTClient.Tests/Modbus_Tests/ModBusTcpClient_tests.cs +++ b/IoTClient.Tests/Modbus_Tests/ModBusTcpClient_tests.cs @@ -1,4 +1,5 @@ using IoTClient.Clients.Modbus; +using IoTClient.Common.Helpers; using IoTClient.Enums; using IoTClient.Models; using System; @@ -22,9 +23,18 @@ namespace IoTClient.Tests.Modbus client = new ModbusTcpClient(new IPEndPoint(ip, port)); } + public bool ShortToBit(int value, int index) + { + var binaryArray = DataConvert.IntToBinaryArray(value, 16); + var length = binaryArray.Length - 16; + return binaryArray[length + index].ToString() == "1"; + } + [Fact] public async Task 短连接自动开关() { + var aa1 = client.ReadUInt16Bit("0.1").Value; + Random rnd = new Random((int)Stopwatch.GetTimestamp()); for (int i = 0; i < 10; i++) { @@ -129,7 +139,7 @@ namespace IoTClient.Tests.Modbus [Fact] public void 批量读取() - { + { var result1 = client.ReadInt16("12"); client.WarningLog = (msg, ex) => diff --git a/IoTClient.Tests/PLC_Tests/OmronFinsClient_Tests.cs b/IoTClient.Tests/PLC_Tests/OmronFinsClient_Tests.cs index 3b18150..852e36a 100644 --- a/IoTClient.Tests/PLC_Tests/OmronFinsClient_Tests.cs +++ b/IoTClient.Tests/PLC_Tests/OmronFinsClient_Tests.cs @@ -24,6 +24,8 @@ namespace IoTClient.Tests.PLCTests var reuslt = client.Open(); + client.ReadInt16("D6402"); + Random rnd = new Random((int)Stopwatch.GetTimestamp()); short short_number = (short)rnd.Next(short.MinValue, short.MaxValue); @@ -37,6 +39,11 @@ namespace IoTClient.Tests.PLCTests client.Write("D300", short_number); client.Write("D301", short_number_1); + client.Write("D100", (short)100); + + Assert.True(client.ReadInt16("D100").Value == 100); + Assert.True(client.ReadInt16("D300").Value == short_number); + Assert.True(client.ReadUInt16("D301").Value == short_number_1); client.Write("D310", int_number); client.Write("D312", int_number_1); @@ -117,6 +124,11 @@ namespace IoTClient.Tests.PLCTests Assert.True(Convert.ToUInt64(result.Value["D354"]) == Convert.ToUInt64(int_number_1)); Assert.True(Convert.ToDouble(result.Value["D358"]) == Convert.ToDouble(float_number)); + client.Write("H400.15", false); + Assert.True(client.ReadBoolean("H400.15").Value == false); + client.Write("H400.15", true); + Assert.True(client.ReadBoolean("H400.15").Value == true); + client.Close(); } diff --git a/IoTClient/Clients/Modbus/Base/ModbusSerialBase.cs b/IoTClient/Clients/Modbus/Base/ModbusSerialBase.cs index eba65d1..fd13fbd 100644 --- a/IoTClient/Clients/Modbus/Base/ModbusSerialBase.cs +++ b/IoTClient/Clients/Modbus/Base/ModbusSerialBase.cs @@ -129,6 +129,38 @@ namespace IoTClient.Clients.Modbus return result.EndTime(); } + /// + /// 按位的方式读取 + /// + /// 寄存器地址:如1.00 ... 1.14、1.15 + /// 站号 + /// 功能码 + /// 按位取值从左边开始取 + /// + public Result ReadInt16Bit(string address, byte stationNumber = 1, byte functionCode = 3, bool left = true) + { + string[] adds = address.Split('.'); + var readResut = Read(adds[0].Trim(), stationNumber, functionCode); + var result = new Result(readResut); + if (result.IsSucceed) + { + result.Value = BitConverter.ToInt16(readResut.Value, 0); + if (adds.Length >= 2) + { + var index = int.Parse(adds[1].Trim()); + var binaryArray = DataConvert.IntToBinaryArray(result.Value, 16); + if (left) + { + var length = binaryArray.Length - 16; + result.Value = short.Parse(binaryArray[length + index].ToString()); + } + else + result.Value = short.Parse(binaryArray[binaryArray.Length - 1 - index].ToString()); + } + } + return result.EndTime(); + } + /// /// 读取UInt16 /// @@ -145,6 +177,38 @@ namespace IoTClient.Clients.Modbus return result.EndTime(); } + /// + /// 按位的方式读取 + /// + /// 寄存器地址:如1.00 ... 1.14、1.15 + /// 站号 + /// 功能码 + /// 按位取值从左边开始取 + /// + public Result ReadUInt16Bit(string address, byte stationNumber = 1, byte functionCode = 3, bool left = true) + { + string[] adds = address.Split('.'); + var readResut = Read(adds[0].Trim(), stationNumber, functionCode); + var result = new Result(readResut); + if (result.IsSucceed) + { + result.Value = BitConverter.ToUInt16(readResut.Value, 0); + if (adds.Length >= 2) + { + var index = int.Parse(adds[1].Trim()); + var binaryArray = DataConvert.IntToBinaryArray(result.Value, 16); + if (left) + { + var length = binaryArray.Length - 16; + result.Value = ushort.Parse(binaryArray[length + index].ToString()); + } + else + result.Value = ushort.Parse(binaryArray[binaryArray.Length - 1 - index].ToString()); + } + } + return result.EndTime(); + } + /// /// 读取Int32 /// diff --git a/IoTClient/Clients/Modbus/Interfaces/IModbusClient.cs b/IoTClient/Clients/Modbus/Interfaces/IModbusClient.cs index df33d24..0369e6f 100644 --- a/IoTClient/Clients/Modbus/Interfaces/IModbusClient.cs +++ b/IoTClient/Clients/Modbus/Interfaces/IModbusClient.cs @@ -59,6 +59,16 @@ namespace IoTClient.Clients.Modbus /// Result ReadInt16(string address, byte stationNumber = 1, byte functionCode = 3); + /// + /// 按位的方式读取 + /// + /// 寄存器地址:如1.00 ... 1.14、1.15 + /// 站号 + /// 功能码 + /// 按位取值从左边开始取 + /// + Result ReadInt16Bit(string address, byte stationNumber = 1, byte functionCode = 3, bool left = true); + /// /// 从批量读取的数据字节提取对应的地址数据 /// @@ -86,6 +96,16 @@ namespace IoTClient.Clients.Modbus /// Result ReadUInt16(string beginAddress, string address, byte[] values); + /// + /// 按位的方式读取 + /// + /// 寄存器地址:如1.00 ... 1.14、1.15 + /// 站号 + /// 功能码 + /// 按位取值从左边开始取 + /// + Result ReadUInt16Bit(string address, byte stationNumber = 1, byte functionCode = 3, bool left = true); + /// /// 读取Int32 /// diff --git a/IoTClient/Clients/Modbus/ModbusRtuClient.cs b/IoTClient/Clients/Modbus/ModbusRtuClient.cs index 57381c7..3b99bc1 100644 --- a/IoTClient/Clients/Modbus/ModbusRtuClient.cs +++ b/IoTClient/Clients/Modbus/ModbusRtuClient.cs @@ -65,6 +65,11 @@ namespace IoTClient.Clients.Modbus result.Err = "响应结果CRC16验证失败"; //return result.EndTime(); } + else if (ModbusHelper.VerifyFunctionCode(functionCode, responsePackage[1])) + { + result.IsSucceed = false; + result.Err = ModbusHelper.ErrMsg(responsePackage[2]); + } byte[] resultData = new byte[responsePackage.Length - 2 - 3]; Array.Copy(responsePackage, 3, resultData, 0, resultData.Length); @@ -123,6 +128,11 @@ namespace IoTClient.Clients.Modbus result.Err = "响应结果CRC16验证失败"; //return result.EndTime(); } + else if (ModbusHelper.VerifyFunctionCode(functionCode, responsePackage[1])) + { + result.IsSucceed = false; + result.Err = ModbusHelper.ErrMsg(responsePackage[2]); + } byte[] resultBuffer = new byte[responsePackage.Length - 2]; Buffer.BlockCopy(responsePackage, 0, resultBuffer, 0, resultBuffer.Length); result.Response = string.Join(" ", responsePackage.Select(t => t.ToString("X2"))); @@ -175,6 +185,11 @@ namespace IoTClient.Clients.Modbus result.Err = "响应结果CRC16验证失败"; //return result.EndTime(); } + else if (ModbusHelper.VerifyFunctionCode(functionCode, responsePackage[1])) + { + result.IsSucceed = false; + result.Err = ModbusHelper.ErrMsg(responsePackage[2]); + } byte[] resultBuffer = new byte[responsePackage.Length - 2]; Array.Copy(responsePackage, 0, resultBuffer, 0, resultBuffer.Length); result.Response = string.Join(" ", responsePackage.Select(t => t.ToString("X2"))); diff --git a/IoTClient/Clients/Modbus/ModbusRtuOverTcpClient.cs b/IoTClient/Clients/Modbus/ModbusRtuOverTcpClient.cs index 80718e2..fa95e9b 100644 --- a/IoTClient/Clients/Modbus/ModbusRtuOverTcpClient.cs +++ b/IoTClient/Clients/Modbus/ModbusRtuOverTcpClient.cs @@ -230,6 +230,38 @@ namespace IoTClient.Clients.Modbus return result.EndTime(); } + /// + /// 按位的方式读取 + /// + /// 寄存器地址:如1.00 ... 1.14、1.15 + /// 站号 + /// 功能码 + /// 按位取值从左边开始取 + /// + public Result ReadInt16Bit(string address, byte stationNumber = 1, byte functionCode = 3, bool left = true) + { + string[] adds = address.Split('.'); + var readResut = Read(adds[0].Trim(), stationNumber, functionCode); + var result = new Result(readResut); + if (result.IsSucceed) + { + result.Value = BitConverter.ToInt16(readResut.Value, 0); + if (adds.Length >= 2) + { + var index = int.Parse(adds[1].Trim()); + var binaryArray = DataConvert.IntToBinaryArray(result.Value, 16); + if (left) + { + var length = binaryArray.Length - 16; + result.Value = short.Parse(binaryArray[length + index].ToString()); + } + else + result.Value = short.Parse(binaryArray[binaryArray.Length - 1 - index].ToString()); + } + } + return result.EndTime(); + } + /// /// 读取UInt16 /// @@ -246,6 +278,38 @@ namespace IoTClient.Clients.Modbus return result.EndTime(); } + /// + /// 按位的方式读取 + /// + /// 寄存器地址:如1.00 ... 1.14、1.15 + /// 站号 + /// 功能码 + /// 按位取值从左边开始取 + /// + public Result ReadUInt16Bit(string address, byte stationNumber = 1, byte functionCode = 3, bool left = true) + { + string[] adds = address.Split('.'); + var readResut = Read(adds[0].Trim(), stationNumber, functionCode); + var result = new Result(readResut); + if (result.IsSucceed) + { + result.Value = BitConverter.ToUInt16(readResut.Value, 0); + if (adds.Length >= 2) + { + var index = int.Parse(adds[1].Trim()); + var binaryArray = DataConvert.IntToBinaryArray(result.Value, 16); + if (left) + { + var length = binaryArray.Length - 16; + result.Value = ushort.Parse(binaryArray[length + index].ToString()); + } + else + result.Value = ushort.Parse(binaryArray[binaryArray.Length - 1 - index].ToString()); + } + } + return result.EndTime(); + } + /// /// 读取Int32 /// diff --git a/IoTClient/Clients/Modbus/ModbusTcpClient.cs b/IoTClient/Clients/Modbus/ModbusTcpClient.cs index d6cd1e4..e3c376a 100644 --- a/IoTClient/Clients/Modbus/ModbusTcpClient.cs +++ b/IoTClient/Clients/Modbus/ModbusTcpClient.cs @@ -183,6 +183,11 @@ namespace IoTClient.Clients.Modbus result.Err = $"读取 地址:{address} 站号:{stationNumber} 功能码:{functionCode} 失败。响应结果校验失败"; socket?.SafeClose(); } + else if (ModbusHelper.VerifyFunctionCode(functionCode, dataPackage[7])) + { + result.IsSucceed = false; + result.Err = ModbusHelper.ErrMsg(dataPackage[8]); + } } catch (SocketException ex) { @@ -220,6 +225,38 @@ namespace IoTClient.Clients.Modbus return result.EndTime(); } + /// + /// 按位的方式读取 + /// + /// 寄存器地址:如1.00 ... 1.14、1.15 + /// 站号 + /// 功能码 + /// 按位取值从左边开始取 + /// + public Result ReadInt16Bit(string address, byte stationNumber = 1, byte functionCode = 3, bool left = true) + { + string[] adds = address.Split('.'); + var readResut = Read(adds[0].Trim(), stationNumber, functionCode); + var result = new Result(readResut); + if (result.IsSucceed) + { + result.Value = BitConverter.ToInt16(readResut.Value, 0); + if (adds.Length >= 2) + { + var index = int.Parse(adds[1].Trim()); + var binaryArray = DataConvert.IntToBinaryArray(result.Value, 16); + if (left) + { + var length = binaryArray.Length - 16; + result.Value = short.Parse(binaryArray[length + index].ToString()); + } + else + result.Value = short.Parse(binaryArray[binaryArray.Length - 1 - index].ToString()); + } + } + return result.EndTime(); + } + /// /// 读取Int16类型数据 /// @@ -247,6 +284,38 @@ namespace IoTClient.Clients.Modbus return result.EndTime(); } + /// + /// 按位的方式读取 + /// + /// 寄存器地址:如1.00 ... 1.14、1.15 + /// 站号 + /// 功能码 + /// 按位取值从左边开始取 + /// + public Result ReadUInt16Bit(string address, byte stationNumber = 1, byte functionCode = 3, bool left = true) + { + string[] adds = address.Split('.'); + var readResut = Read(adds[0].Trim(), stationNumber, functionCode); + var result = new Result(readResut); + if (result.IsSucceed) + { + result.Value = BitConverter.ToUInt16(readResut.Value, 0); + if (adds.Length >= 2) + { + var index = int.Parse(adds[1].Trim()); + var binaryArray = DataConvert.IntToBinaryArray(result.Value, 16); + if (left) + { + var length = binaryArray.Length - 16; + result.Value = ushort.Parse(binaryArray[length + index].ToString()); + } + else + result.Value = ushort.Parse(binaryArray[binaryArray.Length - 1 - index].ToString()); + } + } + return result.EndTime(); + } + /// /// 读取UInt16类型数据 /// @@ -1053,7 +1122,7 @@ namespace IoTClient.Clients.Modbus result.IsSucceed = tempResult.IsSucceed; result.Exception = tempResult.Exception; result.ErrCode = tempResult.ErrCode; - result.Err = $"读取 地址:{minAddress} 站号:{stationNumber} 功能码:{functionCode} 失败。{tempResult.Err}"; + result.Err = tempResult.Err;// $"读取 地址:{minAddress} 站号:{stationNumber} 功能码:{functionCode} 失败。{tempResult.Err}"; result.AddErr2List(); return result.EndTime(); } @@ -1146,6 +1215,11 @@ namespace IoTClient.Clients.Modbus result.Err = "响应结果校验失败"; socket?.SafeClose(); } + else if (ModbusHelper.VerifyFunctionCode(functionCode, dataPackage[7])) + { + result.IsSucceed = false; + result.Err = ModbusHelper.ErrMsg(dataPackage[8]); + } } catch (SocketException ex) { @@ -1203,6 +1277,11 @@ namespace IoTClient.Clients.Modbus result.Err = "响应结果校验失败"; socket?.SafeClose(); } + else if (ModbusHelper.VerifyFunctionCode(functionCode, dataPackage[7])) + { + result.IsSucceed = false; + result.Err = ModbusHelper.ErrMsg(dataPackage[8]); + } } catch (SocketException ex) { diff --git a/IoTClient/Clients/PLC/OmronFinsClient.cs b/IoTClient/Clients/PLC/OmronFinsClient.cs index 2c61d3c..b31a0fc 100644 --- a/IoTClient/Clients/PLC/OmronFinsClient.cs +++ b/IoTClient/Clients/PLC/OmronFinsClient.cs @@ -221,7 +221,7 @@ namespace IoTClient.Clients.PLC Array.Copy(dataPackage, dataPackage.Length - length, responseData, 0, length); result.Response = string.Join(" ", dataPackage.Select(t => t.ToString("X2"))); if (setEndian) - result.Value = responseData.ToArray().ByteFormatting(endianFormat, false); + result.Value = responseData.ToArray().ByteFormatting2(endianFormat, false); else result.Value = responseData.ToArray(); } @@ -388,7 +388,7 @@ namespace IoTClient.Clients.PLC { var interval = (addressInt - startAddressInt) / 2; var offset = (addressInt - startAddressInt) % 2 * 2;//取余 乘以2(每个地址16位,占两个字节) - var byteArry = values.Skip(interval * 2 * 2 + offset).Take(2 * 2).ToArray().ByteFormatting(endianFormat, false); + var byteArry = values.Skip(interval * 2 * 2 + offset).Take(2 * 2).ToArray().ByteFormatting2(endianFormat, false); return new Result { Value = BitConverter.ToInt32(byteArry, 0) @@ -424,7 +424,7 @@ namespace IoTClient.Clients.PLC { var interval = (addressInt - startAddressInt) / 2; var offset = (addressInt - startAddressInt) % 2 * 2;//取余 乘以2(每个地址16位,占两个字节) - var byteArry = values.Skip(interval * 2 * 2 + offset).Take(2 * 2).ToArray().ByteFormatting(endianFormat, false); + var byteArry = values.Skip(interval * 2 * 2 + offset).Take(2 * 2).ToArray().ByteFormatting2(endianFormat, false); return new Result { Value = BitConverter.ToUInt32(byteArry, 0) @@ -460,7 +460,7 @@ namespace IoTClient.Clients.PLC { var interval = (addressInt - startAddressInt) / 4; var offset = (addressInt - startAddressInt) % 4 * 2; - var byteArry = values.Skip(interval * 2 * 4 + offset).Take(2 * 4).ToArray().ByteFormatting(endianFormat, false); + var byteArry = values.Skip(interval * 2 * 4 + offset).Take(2 * 4).ToArray().ByteFormatting2(endianFormat, false); return new Result { Value = BitConverter.ToInt64(byteArry, 0) @@ -496,7 +496,7 @@ namespace IoTClient.Clients.PLC { var interval = (addressInt - startAddressInt) / 4; var offset = (addressInt - startAddressInt) % 4 * 2; - var byteArry = values.Skip(interval * 2 * 4 + offset).Take(2 * 4).ToArray().ByteFormatting(endianFormat, false); + var byteArry = values.Skip(interval * 2 * 4 + offset).Take(2 * 4).ToArray().ByteFormatting2(endianFormat, false); return new Result { Value = BitConverter.ToUInt64(byteArry, 0) @@ -532,7 +532,7 @@ namespace IoTClient.Clients.PLC { var interval = (addressInt - beginAddressInt) / 2; var offset = (addressInt - beginAddressInt) % 2 * 2;//取余 乘以2(每个地址16位,占两个字节) - var byteArry = values.Skip(interval * 2 * 2 + offset).Take(2 * 2).ToArray().ByteFormatting(endianFormat, false); + var byteArry = values.Skip(interval * 2 * 2 + offset).Take(2 * 2).ToArray().ByteFormatting2(endianFormat, false); return new Result { Value = BitConverter.ToSingle(byteArry, 0) @@ -568,7 +568,7 @@ namespace IoTClient.Clients.PLC { var interval = (addressInt - beginAddressInt) / 4; var offset = (addressInt - beginAddressInt) % 4 * 2; - var byteArry = values.Skip(interval * 2 * 4 + offset).Take(2 * 4).ToArray().ByteFormatting(endianFormat, false); + var byteArry = values.Skip(interval * 2 * 4 + offset).Take(2 * 4).ToArray().ByteFormatting2(endianFormat, false); return new Result { Value = BitConverter.ToDouble(byteArry, 0) @@ -607,7 +607,7 @@ namespace IoTClient.Clients.PLC Result result = new Result(); try { - data = data.Reverse().ToArray().ByteFormatting(endianFormat); + data = data.Reverse().ToArray().ByteFormatting2(endianFormat); //发送写入信息 var arg = ConvertArg(address, isBit: isBit); byte[] command = GetWriteCommand(arg, data); @@ -842,7 +842,7 @@ namespace IoTClient.Clients.PLC addressInfo.BitCode = 0x02; addressInfo.WordCode = 0x82; addressInfo.TypeChar = address.Substring(0, 1); - addressInfo.BeginAddress = Convert.ToInt32(address.Substring(1)); + addressInfo.BeginAddress = Convert.ToInt32(address.Substring(1).Split('.')[0]); break; } case 'C'://CIO区 @@ -850,7 +850,7 @@ namespace IoTClient.Clients.PLC addressInfo.BitCode = 0x30; addressInfo.WordCode = 0xB0; addressInfo.TypeChar = address.Substring(0, 1); - addressInfo.BeginAddress = Convert.ToInt32(address.Substring(1)); + addressInfo.BeginAddress = Convert.ToInt32(address.Substring(1).Split('.')[0]); break; } case 'W'://WR区 @@ -858,7 +858,7 @@ namespace IoTClient.Clients.PLC addressInfo.BitCode = 0x31; addressInfo.WordCode = 0xB1; addressInfo.TypeChar = address.Substring(0, 1); - addressInfo.BeginAddress = Convert.ToInt32(address.Substring(1)); + addressInfo.BeginAddress = Convert.ToInt32(address.Substring(1).Split('.')[0]); break; } case 'H'://HR区 @@ -866,7 +866,7 @@ namespace IoTClient.Clients.PLC addressInfo.BitCode = 0x32; addressInfo.WordCode = 0xB2; addressInfo.TypeChar = address.Substring(0, 1); - addressInfo.BeginAddress = Convert.ToInt32(address.Substring(1)); + addressInfo.BeginAddress = Convert.ToInt32(address.Substring(1).Split('.')[0]); break; } case 'A'://AR区 @@ -874,7 +874,7 @@ namespace IoTClient.Clients.PLC addressInfo.BitCode = 0x33; addressInfo.WordCode = 0xB3; addressInfo.TypeChar = address.Substring(0, 1); - addressInfo.BeginAddress = Convert.ToInt32(address.Substring(1)); + addressInfo.BeginAddress = Convert.ToInt32(address.Substring(1).Split('.')[0]); break; } case 'E': @@ -1070,9 +1070,11 @@ namespace IoTClient.Clients.PLC switch (tempMax.DataTypeEnum) { case DataTypeEnum.Bool: + throw new Exception("暂时不支持Bool类型批量读取"); case DataTypeEnum.Byte: - readLength = tempMax.BeginAddress + 1 - minAddress; - break; + throw new Exception("暂时不支持Byte类型批量读取"); + //readLength = tempMax.BeginAddress + 1 - minAddress; + //break; case DataTypeEnum.Int16: case DataTypeEnum.UInt16: readLength = tempMax.BeginAddress * 2 + 2 - minAddress * 2; diff --git a/IoTClient/Common/Helpers/DataConvert.cs b/IoTClient/Common/Helpers/DataConvert.cs index efae6f2..39798aa 100644 --- a/IoTClient/Common/Helpers/DataConvert.cs +++ b/IoTClient/Common/Helpers/DataConvert.cs @@ -115,11 +115,12 @@ namespace IoTClient.Common.Helpers /// Int转二进制 /// /// + /// 补0长度 /// - public static string IntToBinaryArray(this int value) + public static string IntToBinaryArray(this int value, int minLength = 0) { //Convert.ToString(12,2); // 将12转为2进制字符串,结果 “1100” - return Convert.ToString(value, 2); + return Convert.ToString(value, 2).PadLeft(minLength, '0'); } /// diff --git a/IoTClient/Common/Helpers/EndianConversion.cs b/IoTClient/Common/Helpers/EndianConversion.cs index 5e63584..bfcb2f3 100644 --- a/IoTClient/Common/Helpers/EndianConversion.cs +++ b/IoTClient/Common/Helpers/EndianConversion.cs @@ -116,5 +116,53 @@ namespace IoTClient.Common.Helpers } return buffer; } + + /// + /// 字节格式转换 + /// + /// + /// + /// 是否经过了反转 + /// + public static byte[] ByteFormatting2(this byte[] value, EndianFormat format = EndianFormat.ABCD, bool reverse = true) + { + if (!reverse) + { + switch (format) + { + case EndianFormat.ABCD: + format = EndianFormat.DCBA; + break; + case EndianFormat.BADC: + format = EndianFormat.CDAB; + break; + case EndianFormat.CDAB: + format = EndianFormat.BADC; + break; + case EndianFormat.DCBA: + format = EndianFormat.ABCD; + break; + } + } + + byte[] buffer; + if (value.Length == 2) + { + buffer = new byte[2]; + switch (format) + { + case EndianFormat.BADC: + buffer[0] = value[1]; + buffer[1] = value[0]; + break; + default: + buffer = value; + break; + } + } + else + return ByteFormatting(value, format, true); + return buffer; + } } } diff --git a/IoTClient/Common/Helpers/ModbusHelper.cs b/IoTClient/Common/Helpers/ModbusHelper.cs new file mode 100644 index 0000000..cd3f438 --- /dev/null +++ b/IoTClient/Common/Helpers/ModbusHelper.cs @@ -0,0 +1,62 @@ +using System; + +namespace IoTClient.Common.Helpers +{ + /// + /// 帮助类 + /// + public class ModbusHelper + { + /// + /// 是否为异常功能码 + /// + /// + /// + /// + public static bool VerifyFunctionCode(byte resultCode, byte responseCode) + { + return responseCode - resultCode == 128; + } + + /// + /// 异常码描述 + /// https://www.likecs.com/show-204655077.html?sc=5546 + /// + /// + public static string ErrMsg(byte errCode) + { + var err = "未知异常"; + switch (errCode) + { + case 0x01: + err = $"异常码{errCode}:⾮法功能"; + break; + case 0x02: + err = $"异常码{errCode}:⾮法数据地址"; + break; + case 0x03: + err = $"异常码{errCode}:⾮法数据值"; + break; + case 0x04: + err = $"异常码{errCode}:从站设备故障"; + break; + case 0x05: + err = $"异常码{errCode}:确认"; + break; + case 0x06: + err = $"异常码{errCode}:从属设备忙"; + break; + case 0x08: + err = $"异常码{errCode}:存储奇偶性差错"; + break; + case 0x0A: + err = $"异常码{errCode}:不可⽤⽹关路径"; + break; + case 0x0B: + err = $"异常码{errCode}:⽹关⽬标设备响应失败"; + break; + } + return err; + } + } +} diff --git a/IoTClient/IoTClient.csproj b/IoTClient/IoTClient.csproj index 9e91b80..8e719ea 100644 --- a/IoTClient/IoTClient.csproj +++ b/IoTClient/IoTClient.csproj @@ -12,7 +12,7 @@ Copyright (c) 2022 农码一生. All rights reserved. git https://github.com/zhaopeiym/IoTClient - IoT,物联网,PLC,Modbus,Bacnet + Modbus,Bacnet,PLC,S7,ModbusTcp,三菱,西门子,欧姆龙,IoT,物联网,边缘计算 https://user-images.githubusercontent.com/5820324/66972725-12bccf80-f0c8-11e9-9468-3cfc57915dc9.png diff --git a/IoTClient/IoTClient/IoTClient.xml b/IoTClient/IoTClient/IoTClient.xml index a5d87c7..8c9ec10 100644 --- a/IoTClient/IoTClient/IoTClient.xml +++ b/IoTClient/IoTClient/IoTClient.xml @@ -53,6 +53,16 @@ 功能码 + + + 按位的方式读取 + + 寄存器地址:如1.00 ... 1.14、1.15 + 站号 + 功能码 + 按位取值从左边开始取 + + 读取UInt16 @@ -62,6 +72,16 @@ 功能码 + + + 按位的方式读取 + + 寄存器地址:如1.00 ... 1.14、1.15 + 站号 + 功能码 + 按位取值从左边开始取 + + 读取Int32 @@ -415,6 +435,16 @@ 功能码 + + + 按位的方式读取 + + 寄存器地址:如1.00 ... 1.14、1.15 + 站号 + 功能码 + 按位取值从左边开始取 + + 从批量读取的数据字节提取对应的地址数据 @@ -442,6 +472,16 @@ + + + 按位的方式读取 + + 寄存器地址:如1.00 ... 1.14、1.15 + 站号 + 功能码 + 按位取值从左边开始取 + + 读取Int32 @@ -836,6 +876,16 @@ 功能码 + + + 按位的方式读取 + + 寄存器地址:如1.00 ... 1.14、1.15 + 站号 + 功能码 + 按位取值从左边开始取 + + 读取UInt16 @@ -845,6 +895,16 @@ 功能码 + + + 按位的方式读取 + + 寄存器地址:如1.00 ... 1.14、1.15 + 站号 + 功能码 + 按位取值从左边开始取 + + 读取Int32 @@ -1206,6 +1266,16 @@ 功能码 + + + 按位的方式读取 + + 寄存器地址:如1.00 ... 1.14、1.15 + 站号 + 功能码 + 按位取值从左边开始取 + + @@ -1216,6 +1286,16 @@ 功能码 + + + 按位的方式读取 + + 寄存器地址:如1.00 ... 1.14、1.15 + 站号 + 功能码 + 按位取值从左边开始取 + + 读取UInt16类型数据 @@ -3286,11 +3366,12 @@ - + Int转二进制 + 补0长度 @@ -3314,6 +3395,15 @@ 是否经过了反转 + + + 字节格式转换 + + + + 是否经过了反转 + + @@ -3348,6 +3438,26 @@ + + + 帮助类 + + + + + 是否为异常功能码 + + + + + + + + 异常码描述 + https://www.likecs.com/show-204655077.html?sc=5546 + + +