diff --git a/IoTClient.Tests/Modbus_Tests/ModBusTcpClient_tests.cs b/IoTClient.Tests/Modbus_Tests/ModBusTcpClient_tests.cs index 95d33b1..6e732bd 100644 --- a/IoTClient.Tests/Modbus_Tests/ModBusTcpClient_tests.cs +++ b/IoTClient.Tests/Modbus_Tests/ModBusTcpClient_tests.cs @@ -5,6 +5,7 @@ using System; using System.Collections.Generic; using System.Diagnostics; using System.Net; +using System.Text; using System.Threading.Tasks; using Xunit; @@ -37,6 +38,7 @@ namespace IoTClient.Tests.Modbus float float_number = rnd.Next(int.MinValue, int.MaxValue) / 100; double double_number = (double)rnd.Next(int.MinValue, int.MaxValue) / 100; bool coil = int_number % 2 == 0; + string orderCode = "WX8200611002" + short_number; #endregion //写入地址:0 值为:short_number 站号:stationNumber 功能码:默认16(也可以自己传入对应的功能码) @@ -51,6 +53,8 @@ namespace IoTClient.Tests.Modbus client.Write("32", coil, stationNumber, 5); + client.Write("100", orderCode, stationNumber); + //写入可能有一定的延时,500毫秒后检验 await Task.Delay(500); @@ -66,6 +70,8 @@ namespace IoTClient.Tests.Modbus Assert.True(client.ReadDouble("28", stationNumber, 3).Value == double_number); Assert.True(client.ReadCoil("32", stationNumber, 1).Value == coil); + + Assert.True(client.ReadString("100", stationNumber, readLength: (ushort)orderCode.Length).Value == orderCode); } } diff --git a/IoTClient/Clients/ModBus/ModBusAsciiClient.cs b/IoTClient/Clients/ModBus/ModBusAsciiClient.cs index 3a60851..e2f8fd9 100644 --- a/IoTClient/Clients/ModBus/ModBusAsciiClient.cs +++ b/IoTClient/Clients/ModBus/ModBusAsciiClient.cs @@ -162,7 +162,7 @@ namespace IoTClient.Clients.Modbus /// /// /// - public override Result Write(string address, byte[] values, byte stationNumber = 1, byte functionCode = 16) + public override Result Write(string address, byte[] values, byte stationNumber = 1, byte functionCode = 16, bool byteFormatting = true) { if (isAutoOpen) Connect(); diff --git a/IoTClient/Clients/ModBus/ModBusRtuClient.cs b/IoTClient/Clients/ModBus/ModBusRtuClient.cs index 51114b4..4225bc8 100644 --- a/IoTClient/Clients/ModBus/ModBusRtuClient.cs +++ b/IoTClient/Clients/ModBus/ModBusRtuClient.cs @@ -142,7 +142,7 @@ namespace IoTClient.Clients.Modbus /// /// /// - public override Result Write(string address, byte[] values, byte stationNumber = 1, byte functionCode = 16) + public override Result Write(string address, byte[] values, byte stationNumber = 1, byte functionCode = 16, bool byteFormatting = true) { if (isAutoOpen) Connect(); diff --git a/IoTClient/Clients/ModBus/ModBusTcpClient.cs b/IoTClient/Clients/ModBus/ModBusTcpClient.cs index 70d993e..a5895a2 100644 --- a/IoTClient/Clients/ModBus/ModBusTcpClient.cs +++ b/IoTClient/Clients/ModBus/ModBusTcpClient.cs @@ -6,6 +6,7 @@ using System.Collections.Generic; using System.Linq; using System.Net; using System.Net.Sockets; +using System.Text; namespace IoTClient.Clients.Modbus { @@ -469,6 +470,34 @@ namespace IoTClient.Clients.Modbus return ReadDouble(address.ToString(), stationNumber, functionCode); } + /// + /// 读取字符串 + /// + /// 地址 + /// 站号 + /// 功能码 + /// 编码 + /// 读取长度 + /// + public Result ReadString(string address, byte stationNumber = 1, byte functionCode = 3, Encoding encoding = null, ushort readLength = 10) + { + if (encoding == null) encoding = Encoding.ASCII; + + readLength = (ushort)Math.Ceiling((float)readLength / 2); + var readResut = Read(address, stationNumber, functionCode, readLength: readLength, byteFormatting: false); + var result = new Result() + { + IsSucceed = readResut.IsSucceed, + Err = readResut.Err, + ErrList = readResut.ErrList, + Requst = readResut.Requst, + Response = readResut.Response, + }; + if (result.IsSucceed) + result.Value = encoding.GetString(readResut.Value.Reverse().ToArray())?.Replace("\0", ""); + return result.EndTime(); + } + /// /// 读取线圈类型数据 /// @@ -973,103 +1002,6 @@ namespace IoTClient.Clients.Modbus return ReadDiscrete(beginAddress.ToString(), address.ToString(), values); } - #region 假的批量 注释 - ///// - ///// 分批读取【假的批量,内部实际还是循环读取】 - ///// - ///// 地址集合 - ///// 批量读取数量 - ///// - //public Result> BatchRead(Dictionary addresses, int batchNumber = 19) - //{ - // var result = new Result>(); - // result.Value = new Dictionary(); - - // var batchCount = Math.Ceiling((float)addresses.Count / batchNumber); - // for (int i = 0; i < batchCount; i++) - // { - // var tempAddresses = addresses.Skip(i * batchNumber).Take(batchNumber).ToDictionary(t => t.Key, t => t.Value); - // var tempResult = BatchRead(tempAddresses); - // if (tempResult.IsSucceed) - // { - // foreach (var item in tempResult.Value) - // { - // result.Value.Add(item.Key, item.Value); - // } - // } - // else - // { - // result.IsSucceed = false; - // result.Err = tempResult.Err; - // } - // } - // return result.EndTime(); - //} - - //private Result> BatchRead(Dictionary addresses) - //{ - // var result = new Result>(); - // result.Value = new Dictionary(); - // try - // { - // foreach (var item in addresses) - // { - // var richText = item.Key.Split('_'); - // if (richText.Length < 2) - // continue; //必须传入站号 - // var stationNumber = byte.Parse(richText[0]); - // var addresse = richText[1]; - // var functionCode = richText.Length >= 3 ? byte.Parse(richText[2]) : (byte)3; - // object value; - // switch (item.Value) - // { - // case DataTypeEnum.Bool: - // value = ReadDiscrete(addresse, stationNumber, functionCode).Value; - // break; - // //case DataTypeEnum.Byte: - // // value = readResut[0]; - // // break; - // case DataTypeEnum.Int16: - // value = ReadInt16(addresse, stationNumber, functionCode).Value; - // break; - // case DataTypeEnum.UInt16: - // value = ReadUInt16(addresse, stationNumber, functionCode).Value; - // break; - // case DataTypeEnum.Int32: - // value = ReadInt32(addresse, stationNumber, functionCode).Value; - // break; - // case DataTypeEnum.UInt32: - // value = ReadUInt32(addresse, stationNumber, functionCode).Value; - // break; - // case DataTypeEnum.Int64: - // value = ReadInt64(addresse, stationNumber, functionCode).Value; - // break; - // case DataTypeEnum.UInt64: - // value = ReadUInt64(addresse, stationNumber, functionCode).Value; - // break; - // case DataTypeEnum.Float: - // value = ReadFloat(addresse, stationNumber, functionCode).Value; - // break; - // case DataTypeEnum.Double: - // value = ReadDouble(addresse, stationNumber, functionCode).Value; - // break; - // default: - // throw new Exception($"未定义数据类型:{item.Value}"); - // } - // result.Value.Add(item.Key, value); - // } - // } - // catch (Exception ex) - // { - // result.IsSucceed = false; - // result.Err = ex.Message; - // result.Exception = ex; - // result.ErrList.Add(ex.Message); - // } - // return result.EndTime(); - //} - #endregion - /// /// 分批读取(批量读取,内部进行批量计算读取) /// @@ -1279,15 +1211,17 @@ namespace IoTClient.Clients.Modbus /// 批量读取的值 /// 站号 /// 功能码 + /// 大小端设置 /// - public Result Write(string address, byte[] values, byte stationNumber = 1, byte functionCode = 16) + public Result Write(string address, byte[] values, byte stationNumber = 1, byte functionCode = 16, bool byteFormatting = true) { if (!socket?.Connected ?? true) Connect(); var result = new Result(); try { - values = values.ByteFormatting(format); + if (byteFormatting) + values = values.ByteFormatting(format); var chenkHead = GetCheckHead(functionCode); var command = GetWriteCommand(address, values, stationNumber, functionCode, chenkHead); result.Requst = string.Join(" ", command.Select(t => t.ToString("X2"))); @@ -1426,6 +1360,24 @@ namespace IoTClient.Clients.Modbus var values = BitConverter.GetBytes(value).Reverse().ToArray(); return Write(address, values, stationNumber, functionCode); } + + /// + /// 写字符串 + /// + /// 地址 + /// 字符串值 + /// 站号 + /// 功能码 + /// 编码 + /// + public Result Write(string address, string value, byte stationNumber = 1, byte functionCode = 16, Encoding encoding = null) + { + if (encoding == null) encoding = Encoding.ASCII; + if (value.Length % 2 == 1) + value = value + "\0"; + var values = encoding.GetBytes(value); + return Write(address, values, stationNumber, functionCode, false); + } #endregion #region 获取命令 diff --git a/IoTClient/Clients/Modbus/Base/ModbusSerialBase.cs b/IoTClient/Clients/Modbus/Base/ModbusSerialBase.cs index c396e90..d26464f 100644 --- a/IoTClient/Clients/Modbus/Base/ModbusSerialBase.cs +++ b/IoTClient/Clients/Modbus/Base/ModbusSerialBase.cs @@ -843,7 +843,7 @@ namespace IoTClient.Clients.Modbus /// /// /// - public abstract Result Write(string address, byte[] values, byte stationNumber = 1, byte functionCode = 16); + public abstract Result Write(string address, byte[] values, byte stationNumber = 1, byte functionCode = 16, bool byteFormatting = true); /// /// 写入 diff --git a/IoTClient/Clients/Modbus/Interfaces/IModbusClient.cs b/IoTClient/Clients/Modbus/Interfaces/IModbusClient.cs index 5b77696..a30f9ea 100644 --- a/IoTClient/Clients/Modbus/Interfaces/IModbusClient.cs +++ b/IoTClient/Clients/Modbus/Interfaces/IModbusClient.cs @@ -251,7 +251,7 @@ namespace IoTClient.Clients.Modbus /// /// /// - Result Write(string address, byte[] values, byte stationNumber = 1, byte functionCode = 16); + Result Write(string address, byte[] values, byte stationNumber = 1, byte functionCode = 16, bool byteFormatting = true); /// /// 写入 diff --git a/IoTClient/Clients/Modbus/ModbusRtuOverTcpClient.cs b/IoTClient/Clients/Modbus/ModbusRtuOverTcpClient.cs index 81f8b82..5f8c3d9 100644 --- a/IoTClient/Clients/Modbus/ModbusRtuOverTcpClient.cs +++ b/IoTClient/Clients/Modbus/ModbusRtuOverTcpClient.cs @@ -985,7 +985,7 @@ namespace IoTClient.Clients.Modbus /// /// /// - public Result Write(string address, byte[] values, byte stationNumber = 1, byte functionCode = 16) + public Result Write(string address, byte[] values, byte stationNumber = 1, byte functionCode = 16, bool byteFormatting = true) { if (isAutoOpen) Connect(); diff --git a/IoTClient/IoTClient/IoTClient.xml b/IoTClient/IoTClient/IoTClient.xml index ffd58f1..b0419a7 100644 --- a/IoTClient/IoTClient/IoTClient.xml +++ b/IoTClient/IoTClient/IoTClient.xml @@ -234,7 +234,7 @@ - + 写入 @@ -583,7 +583,7 @@ - + 写入 @@ -701,7 +701,7 @@ - + 写入 @@ -748,7 +748,7 @@ - + 写入 @@ -991,7 +991,7 @@ - + 写入 @@ -1291,6 +1291,17 @@ 功能码 + + + 读取字符串 + + 地址 + 站号 + 功能码 + 编码 + 编码 + + 读取线圈类型数据 @@ -1523,7 +1534,7 @@ 站号 功能码 - + 写入 @@ -1531,6 +1542,7 @@ 批量读取的值 站号 功能码 + 大小端设置 @@ -1605,6 +1617,17 @@ 站号 功能码 + + + 写字符串 + + 地址 + 字符串值 + 站号 + 功能码 + 编码 + + 获取随机校验头 diff --git a/README.md b/README.md index 802accb..4612a90 100644 --- a/README.md +++ b/README.md @@ -34,6 +34,7 @@ client.Write("20", (ulong)33, 2, 16); //写入ulong类型数值 client.Write("24", (float)33, 2, 16); //写入float类型数值 client.Write("28", (double)33, 2, 16); //写入double类型数值 client.Write("32", true, 2, 5); //写入线圈类型值 +client.Write("100", "orderCode", stationNumber); //写入字符串 //3、读操作 - 参数依次是:地址 、站号 、功能码 var value = client.ReadInt16("4", 2, 3).Value; @@ -49,6 +50,7 @@ client.ReadFloat("24", stationNumber, 3); //float类型数据读取 client.ReadDouble("28", stationNumber, 3); //double类型数据读取 client.ReadCoil("32", stationNumber, 1); //线圈类型数据读取 client.ReadDiscrete("32", stationNumber, 2);//离散类型数据读取 +client.ReadString("100", stationNumber,10); //读取字符串 //4、如果没有主动Open,则会每次读写操作的时候自动打开自动和关闭连接,这样会使读写效率大大减低。所以建议手动Open和Close。 client.Open();