diff --git a/IoTClient.Tests/Modbus_Tests/ModBusTcpClient_tests.cs b/IoTClient.Tests/Modbus_Tests/ModBusTcpClient_tests.cs
index 7cb97d9..4d7d01b 100644
--- a/IoTClient.Tests/Modbus_Tests/ModBusTcpClient_tests.cs
+++ b/IoTClient.Tests/Modbus_Tests/ModBusTcpClient_tests.cs
@@ -1,7 +1,9 @@
using IoTClient.Clients.Modbus;
using IoTClient.Enums;
using IoTClient.Models;
+using System;
using System.Collections.Generic;
+using System.Diagnostics;
using System.Net;
using System.Threading.Tasks;
using Xunit;
@@ -19,6 +21,106 @@ namespace IoTClient.Tests.Modbus
client = new ModbusTcpClient(new IPEndPoint(ip, port));
}
+ [Fact]
+ public async Task 短连接自动开关()
+ {
+ Random rnd = new Random((int)Stopwatch.GetTimestamp());
+ for (int i = 0; i < 10; i++)
+ {
+ #region 生产随机数
+ short short_number = (short)rnd.Next(short.MinValue, short.MaxValue);
+ ushort ushort_number = (ushort)rnd.Next(ushort.MinValue, ushort.MaxValue);
+ int int_number = rnd.Next(int.MinValue, int.MaxValue);
+ uint uint_number = (uint)Math.Abs(rnd.Next(int.MinValue, int.MaxValue));
+ long long_number = rnd.Next(int.MinValue, int.MaxValue);
+ ulong ulong_number = (ulong)Math.Abs(rnd.Next(int.MinValue, int.MaxValue));
+ 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;
+ #endregion
+
+ //写入地址:0 值为:short_number 站号:stationNumber 功能码:默认16(也可以自己传入对应的功能码)
+ client.Write("0", short_number, stationNumber, 16);
+ client.Write("4", ushort_number, stationNumber, 16);
+ client.Write("8", int_number, stationNumber, 16);
+ client.Write("12", uint_number, stationNumber, 16);
+ client.Write("16", long_number, stationNumber, 16);
+ client.Write("20", ulong_number, stationNumber, 16);
+ client.Write("24", float_number, stationNumber, 16);
+ client.Write("28", double_number, stationNumber, 16);
+
+ client.Write("32", coil, stationNumber, 5);
+
+ //写入可能有一定的延时,500毫秒后检验
+ await Task.Delay(500);
+
+ //读取地址:0 站号:stationNumber 功能码:默认16(也可以自己传入对应的功能码)
+ var read_short_number = client.ReadInt16("0", stationNumber, 3).Value;
+ Assert.True(read_short_number == short_number);
+ Assert.True(client.ReadUInt16("4", stationNumber, 3).Value == ushort_number);
+ Assert.True(client.ReadInt32("8", stationNumber, 3).Value == int_number);
+ Assert.True(client.ReadUInt32("12", stationNumber, 3).Value == uint_number);
+ Assert.True(client.ReadInt64("16", stationNumber, 3).Value == long_number);
+ Assert.True(client.ReadUInt64("20", stationNumber, 3).Value == ulong_number);
+ Assert.True(client.ReadFloat("24", stationNumber, 3).Value == float_number);
+ Assert.True(client.ReadDouble("28", stationNumber, 3).Value == double_number);
+
+ Assert.True(client.ReadCoil("32", stationNumber, 1).Value == coil);
+ }
+ }
+
+ [Fact]
+ public async Task 长连接主动开关()
+ {
+ client.Open();
+
+ Random rnd = new Random((int)Stopwatch.GetTimestamp());
+ for (int i = 0; i < 10; i++)
+ {
+ #region 生产随机数
+ short short_number = (short)rnd.Next(short.MinValue, short.MaxValue);
+ ushort ushort_number = (ushort)rnd.Next(ushort.MinValue, ushort.MaxValue);
+ int int_number = rnd.Next(int.MinValue, int.MaxValue);
+ uint uint_number = (uint)Math.Abs(rnd.Next(int.MinValue, int.MaxValue));
+ long long_number = rnd.Next(int.MinValue, int.MaxValue);
+ ulong ulong_number = (ulong)Math.Abs(rnd.Next(int.MinValue, int.MaxValue));
+ 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;
+ #endregion
+
+ //写入地址:0 值为:short_number 站号:stationNumber 功能码:默认16(也可以自己传入对应的功能码)
+ client.Write("0", short_number, stationNumber, 16);
+ client.Write("4", ushort_number, stationNumber, 16);
+ client.Write("8", int_number, stationNumber, 16);
+ client.Write("12", uint_number, stationNumber, 16);
+ client.Write("16", long_number, stationNumber, 16);
+ client.Write("20", ulong_number, stationNumber, 16);
+ client.Write("24", float_number, stationNumber, 16);
+ client.Write("28", double_number, stationNumber, 16);
+
+ client.Write("32", coil, stationNumber, 5);
+
+ //写入可能有一定的延时,500毫秒后检验
+ await Task.Delay(500);
+
+ //读取地址:0 站号:stationNumber 功能码:默认16(也可以自己传入对应的功能码)
+ var read_short_number = client.ReadInt16("0", stationNumber, 3).Value;
+ Assert.True(read_short_number == short_number);
+ Assert.True(client.ReadUInt16("4", stationNumber, 3).Value == ushort_number);
+ Assert.True(client.ReadInt32("8", stationNumber, 3).Value == int_number);
+ Assert.True(client.ReadUInt32("12", stationNumber, 3).Value == uint_number);
+ Assert.True(client.ReadInt64("16", stationNumber, 3).Value == long_number);
+ Assert.True(client.ReadUInt64("20", stationNumber, 3).Value == ulong_number);
+ Assert.True(client.ReadFloat("24", stationNumber, 3).Value == float_number);
+ Assert.True(client.ReadDouble("28", stationNumber, 3).Value == double_number);
+
+ Assert.True(client.ReadCoil("32", stationNumber, 1).Value == coil);
+ }
+
+ client.Close();
+ }
+
[Fact]
public void 批量读取()
{
@@ -61,91 +163,5 @@ namespace IoTClient.Tests.Modbus
});
var result = client.BatchRead(list);
}
-
- ///
- /// Modbus值的写入有一定的延时,500毫秒后检验
- ///
- ///
- [Fact]
- public async Task 短连接自动开关()
- {
- short Number = 33;
- client.Write("4", Number, stationNumber);
- await Task.Delay(500);
- Assert.True(client.ReadInt16("4", stationNumber).Value == Number);
-
- Number = 34;
- client.Write("4", Number, stationNumber);
- await Task.Delay(500);
- Assert.True(client.ReadInt16("4", stationNumber).Value == Number);
-
- Number = 1;
- client.Write("12", Number, stationNumber);
- await Task.Delay(500);
- Assert.True(client.ReadInt16("12", stationNumber).Value == 1);
-
- Number = 0;
- client.Write("12", Number, stationNumber);
- await Task.Delay(500);
- Assert.True(client.ReadInt16("12", stationNumber).Value == 0);
-
- int numberInt32 = -12;
- client.Write("4", numberInt32, stationNumber);
- await Task.Delay(500);
- Assert.True(client.ReadInt32("4", stationNumber).Value == numberInt32);
-
- float numberFloat = 112;
- client.Write("4", numberFloat, stationNumber);
- await Task.Delay(500);
- Assert.True(client.ReadFloat("4", stationNumber).Value == numberFloat);
-
- double numberDouble = 32;
- client.Write("4", numberDouble, stationNumber);
- await Task.Delay(500);
- Assert.True(client.ReadDouble("4", stationNumber).Value == numberDouble);
- }
-
- [Fact]
- public async Task 长连接主动开关()
- {
- client.Open();
-
- short Number = 33;
- client.Write("4", Number, stationNumber);
- await Task.Delay(500);
- Assert.True(client.ReadInt16("4", stationNumber).Value == Number);
-
- Number = 34;
- client.Write("4", Number, stationNumber);
- await Task.Delay(500);
- Assert.True(client.ReadInt16("4", stationNumber).Value == Number);
-
- Number = 1;
- client.Write("12", Number, stationNumber);
- await Task.Delay(500);
- Assert.True(client.ReadInt16("12", stationNumber).Value == 1);
-
- Number = 0;
- client.Write("12", Number, stationNumber);
- await Task.Delay(500);
- Assert.True(client.ReadInt16("12", stationNumber).Value == 0);
-
- int numberInt32 = -12;
- client.Write("4", numberInt32, stationNumber);
- await Task.Delay(500);
- Assert.True(client.ReadInt32("4", stationNumber).Value == numberInt32);
-
- float numberFloat = 112;
- client.Write("4", numberFloat, stationNumber);
- await Task.Delay(500);
- Assert.True(client.ReadFloat("4", stationNumber).Value == numberFloat);
-
- double numberDouble = 32;
- client.Write("4", numberDouble, stationNumber);
- await Task.Delay(500);
- Assert.True(client.ReadDouble("4", stationNumber).Value == numberDouble);
-
- client.Close();
- }
}
}
diff --git a/IoTClient/Clients/ModBus/ModBusTcpClient.cs b/IoTClient/Clients/ModBus/ModBusTcpClient.cs
index be47c01..6dd2f4a 100644
--- a/IoTClient/Clients/ModBus/ModBusTcpClient.cs
+++ b/IoTClient/Clients/ModBus/ModBusTcpClient.cs
@@ -188,7 +188,7 @@ namespace IoTClient.Clients.Modbus
}
///
- /// 读取Int16
+ /// 读取Int16类型数据
///
/// 寄存器起始地址
/// 站号
@@ -210,13 +210,19 @@ namespace IoTClient.Clients.Modbus
return result.EndTime();
}
+ ///
+ /// 读取Int16类型数据
+ ///
+ /// 寄存器起始地址
+ /// 站号
+ /// 功能码 ReadInt16(int address, byte stationNumber = 1, byte functionCode = 3)
{
return ReadInt16(address.ToString(), stationNumber, functionCode);
}
///
- /// 读取UInt16
+ /// 读取UInt16类型数据
///
/// 寄存器起始地址
/// 站号
@@ -238,13 +244,20 @@ namespace IoTClient.Clients.Modbus
return result.EndTime();
}
+ ///
+ /// 读取UInt16类型数据
+ ///
+ /// 寄存器起始地址
+ /// 站号
+ /// 功能码
+ ///
public Result ReadUInt16(int address, byte stationNumber = 1, byte functionCode = 3)
{
return ReadUInt16(address.ToString(), stationNumber, functionCode);
}
///
- /// 读取Int32
+ /// 读取Int32类型数据
///
/// 寄存器起始地址
/// 站号
@@ -266,6 +279,13 @@ namespace IoTClient.Clients.Modbus
return result.EndTime();
}
+ ///
+ /// 读取Int32类型数据
+ ///
+ /// 寄存器起始地址
+ /// 站号
+ /// 功能码
+ ///
public Result ReadInt32(int address, byte stationNumber = 1, byte functionCode = 3)
{
return ReadInt32(address.ToString(), stationNumber, functionCode);
@@ -273,7 +293,7 @@ namespace IoTClient.Clients.Modbus
///
- /// 读取UInt32
+ /// 读取UInt32类型数据
///
/// 寄存器起始地址
/// 站号
@@ -295,13 +315,20 @@ namespace IoTClient.Clients.Modbus
return result.EndTime();
}
+ ///
+ /// 读取UInt32类型数据
+ ///
+ /// 寄存器起始地址
+ /// 站号
+ /// 功能码
+ ///
public Result ReadUInt32(int address, byte stationNumber = 1, byte functionCode = 3)
{
return ReadUInt32(address.ToString(), stationNumber, functionCode);
}
///
- /// 读取Int64
+ /// 读取Int64类型数据
///
/// 寄存器起始地址
/// 站号
@@ -323,13 +350,20 @@ namespace IoTClient.Clients.Modbus
return result.EndTime();
}
+ ///
+ /// 读取Int64类型数据
+ ///
+ /// 寄存器起始地址
+ /// 站号
+ /// 功能码
+ ///
public Result ReadInt64(int address, byte stationNumber = 1, byte functionCode = 3)
{
return ReadInt64(address.ToString(), stationNumber, functionCode);
}
///
- /// 读取UInt64
+ /// 读取UInt64类型数据
///
/// 寄存器起始地址
/// 站号
@@ -351,13 +385,20 @@ namespace IoTClient.Clients.Modbus
return result.EndTime();
}
+ ///
+ /// 读取UInt64类型数据
+ ///
+ /// 寄存器起始地址
+ /// 站号
+ /// 功能码
+ ///
public Result ReadUInt64(int address, byte stationNumber = 1, byte functionCode = 3)
{
return ReadUInt64(address.ToString(), stationNumber, functionCode);
}
///
- /// 读取Float
+ /// 读取Float类型数据
///
/// 寄存器起始地址
/// 站号
@@ -379,13 +420,20 @@ namespace IoTClient.Clients.Modbus
return result.EndTime();
}
+ ///
+ /// 读取Float类型数据
+ ///
+ /// 寄存器起始地址
+ /// 站号
+ /// 功能码
+ ///
public Result ReadFloat(int address, byte stationNumber = 1, byte functionCode = 3)
{
return ReadFloat(address.ToString(), stationNumber, functionCode);
}
///
- /// 读取Double
+ /// 读取Double类型数据
///
/// 寄存器起始地址
/// 站号
@@ -407,13 +455,20 @@ namespace IoTClient.Clients.Modbus
return result.EndTime();
}
+ ///
+ /// 读取Double类型数据
+ ///
+ /// 寄存器起始地址
+ /// 站号
+ /// 功能码
+ ///
public Result ReadDouble(int address, byte stationNumber = 1, byte functionCode = 3)
{
return ReadDouble(address.ToString(), stationNumber, functionCode);
}
///
- /// 读取线圈
+ /// 读取线圈类型数据
///
/// 寄存器起始地址
/// 站号
@@ -435,17 +490,24 @@ namespace IoTClient.Clients.Modbus
return result.EndTime();
}
+ ///
+ /// 读取线圈类型数据
+ ///
+ /// 寄存器起始地址
+ /// 站号
+ /// 功能码
+ ///
public Result ReadCoil(int address, byte stationNumber = 1, byte functionCode = 1)
{
return ReadCoil(address.ToString(), stationNumber, functionCode);
}
///
- /// 读取离散
+ /// 读取离散类型数据
///
/// 读取地址
- ///
- ///
+ /// 站号
+ /// 功能码
///
public Result ReadDiscrete(string address, byte stationNumber = 1, byte functionCode = 2)
{
@@ -463,6 +525,13 @@ namespace IoTClient.Clients.Modbus
return result.EndTime();
}
+ ///
+ /// 读取离散类型数据
+ ///
+ /// 读取地址
+ /// 站号
+ /// 功能码
+ ///
public Result ReadDiscrete(int address, byte stationNumber = 1, byte functionCode = 2)
{
return ReadDiscrete(address.ToString(), stationNumber, functionCode);
@@ -498,6 +567,13 @@ namespace IoTClient.Clients.Modbus
}
}
+ ///
+ /// 从批量读取的数据字节提取对应的地址数据
+ ///
+ /// 批量读取的起始地址
+ /// 读取地址
+ /// 批量读取的值
+ ///
public Result ReadInt16(int beginAddress, int address, byte[] values)
{
return ReadInt16(beginAddress.ToString(), address.ToString(), values);
@@ -533,6 +609,13 @@ namespace IoTClient.Clients.Modbus
}
}
+ ///
+ /// 从批量读取的数据字节提取对应的地址数据
+ ///
+ /// 批量读取的起始地址
+ /// 读取地址
+ /// 批量读取的值
+ ///
public Result ReadUInt16(int beginAddress, int address, byte[] values)
{
return ReadUInt16(beginAddress.ToString(), address.ToString(), values);
@@ -569,6 +652,13 @@ namespace IoTClient.Clients.Modbus
}
}
+ ///
+ /// 从批量读取的数据字节提取对应的地址数据
+ ///
+ /// 批量读取的起始地址
+ /// 读取地址
+ /// 批量读取的值
+ ///
public Result ReadInt32(int beginAddress, int address, byte[] values)
{
return ReadInt32(beginAddress.ToString(), address.ToString(), values);
@@ -605,6 +695,13 @@ namespace IoTClient.Clients.Modbus
}
}
+ ///
+ /// 从批量读取的数据字节提取对应的地址数据
+ ///
+ /// 批量读取的起始地址
+ /// 读取地址
+ /// 批量读取的值
+ ///
public Result ReadUInt32(int beginAddress, int address, byte[] values)
{
return ReadUInt32(beginAddress.ToString(), address.ToString(), values);
@@ -641,6 +738,13 @@ namespace IoTClient.Clients.Modbus
}
}
+ ///
+ /// 从批量读取的数据字节提取对应的地址数据
+ ///
+ /// 批量读取的起始地址
+ /// 读取地址
+ /// 批量读取的值
+ ///
public Result ReadInt64(int beginAddress, int address, byte[] values)
{
return ReadInt64(beginAddress.ToString(), address.ToString(), values);
@@ -677,6 +781,13 @@ namespace IoTClient.Clients.Modbus
}
}
+ ///
+ /// 从批量读取的数据字节提取对应的地址数据
+ ///
+ /// 批量读取的起始地址
+ /// 读取地址
+ /// 批量读取的值
+ ///
public Result ReadUInt64(int beginAddress, int address, byte[] values)
{
return ReadUInt64(beginAddress.ToString(), address.ToString(), values);
@@ -713,6 +824,13 @@ namespace IoTClient.Clients.Modbus
}
}
+ ///
+ /// 从批量读取的数据字节提取对应的地址数据
+ ///
+ /// 批量读取的起始地址
+ /// 读取地址
+ /// 批量读取的值
+ ///
public Result ReadFloat(int beginAddress, int address, byte[] values)
{
return ReadFloat(beginAddress.ToString(), address.ToString(), values);
@@ -749,6 +867,13 @@ namespace IoTClient.Clients.Modbus
}
}
+ ///
+ /// 从批量读取的数据字节提取对应的地址数据
+ ///
+ /// 批量读取的起始地址
+ /// 读取地址
+ /// 批量读取的值
+ ///
public Result ReadDouble(int beginAddress, int address, byte[] values)
{
return ReadDouble(beginAddress.ToString(), address.ToString(), values);
@@ -788,6 +913,13 @@ namespace IoTClient.Clients.Modbus
}
}
+ ///
+ /// 从批量读取的数据字节提取对应的地址数据
+ ///
+ /// 批量读取的起始地址
+ /// 读取地址
+ /// 批量读取的值
+ ///
public Result ReadCoil(int beginAddress, int address, byte[] values)
{
return ReadCoil(beginAddress.ToString(), address.ToString(), values);
@@ -827,6 +959,13 @@ namespace IoTClient.Clients.Modbus
}
}
+ ///
+ /// 从批量读取的数据字节提取对应的地址数据
+ ///
+ /// 批量读取的起始地址
+ /// 读取地址
+ /// 批量读取的值
+ ///
public Result ReadDiscrete(int beginAddress, int address, byte[] values)
{
return ReadDiscrete(beginAddress.ToString(), address.ToString(), values);
@@ -1088,8 +1227,8 @@ namespace IoTClient.Clients.Modbus
///
/// 读取地址
///
- ///
- ///
+ /// 站号
+ /// 功能码
public Result Write(string address, bool value, byte stationNumber = 1, byte functionCode = 5)
{
if (!socket?.Connected ?? true) Connect();
@@ -1136,8 +1275,8 @@ namespace IoTClient.Clients.Modbus
///
/// 读取地址
/// 批量读取的值
- ///
- ///
+ /// 站号
+ /// 功能码
///
public Result Write(string address, byte[] values, byte stationNumber = 1, byte functionCode = 16)
{
diff --git a/IoTClient/Clients/PLC/OmronFinsClient.cs b/IoTClient/Clients/PLC/OmronFinsClient.cs
index 91fc57d..77d0a96 100644
--- a/IoTClient/Clients/PLC/OmronFinsClient.cs
+++ b/IoTClient/Clients/PLC/OmronFinsClient.cs
@@ -13,6 +13,7 @@ namespace IoTClient.Clients.PLC
{
///
/// 欧姆龙PLC 客户端 - Beta
+ /// https://flat2010.github.io/2020/02/23/Omron-Fins%E5%8D%8F%E8%AE%AE/
///
public class OmronFinsClient : SocketBase, IEthernetClient
{
@@ -24,9 +25,11 @@ namespace IoTClient.Clients.PLC
///
private byte[] BasicCommand = new byte[]
{
- 0x46, 0x49, 0x4E, 0x53, 0x00, 0x00, 0x00, 0x0C,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x01
+ 0x46, 0x49, 0x4E, 0x53,//Magic字段 0x46494E53 对应的ASCII码,即FINS
+ 0x00, 0x00, 0x00, 0x0C,//Length字段 表示其后所有字段的总长度
+ 0x00, 0x00, 0x00, 0x00,//Command字段
+ 0x00, 0x00, 0x00, 0x00,//Error Code字段
+ 0x00, 0x00, 0x00, 0x01 //Client/Server Node Address字段
};
///
@@ -50,9 +53,12 @@ namespace IoTClient.Clients.PLC
public LoggerDelegate WarningLog { get; set; }
///
- /// 单元号地址
+ /// DA2(即Destination unit address,目标单元地址)
+ /// 0x00:PC(CPU)
+ /// 0xFE: SYSMAC NET Link Unit or SYSMAC LINK Unit connected to network;
+ /// 0x10~0x1F:CPU总线单元 ,其值等于10 + 单元号(前端面板中配置的单元号)
///
- public byte UnitNumber { get; set; } = 0x00;
+ public byte UnitAddress { get; set; } = 0x00;
///
///
@@ -61,7 +67,7 @@ namespace IoTClient.Clients.PLC
///
///
///
- public OmronFinsClient(string ip, int port, int timeout = 1500, EndianFormat endianFormat = EndianFormat.CDAB)
+ public OmronFinsClient(string ip, int port = 9600, int timeout = 1500, EndianFormat endianFormat = EndianFormat.CDAB)
{
IpAndPoint = new IPEndPoint(IPAddress.Parse(ip), port); ;
this.timeout = timeout;
@@ -601,19 +607,19 @@ namespace IoTClient.Clients.PLC
tmp.CopyTo(command, 4);
command[11] = 0x02;
- command[16] = 0x80; //信息控制字段
- command[17] = 0x00;
- command[18] = 0x02;
- command[19] = 0x00;
- command[20] = 0x13; //0x13; //01(节点地址:Ip地址的最后一位)
- command[21] = UnitNumber; //单元号地址(传过来)
- command[22] = 0x00;
- command[23] = 0x0B; //0x0B; //01(节点地址:Ip地址的最后一位)
- command[24] = 0x00;
- command[25] = 0x00;
+ command[16] = 0x80; //ICF 信息控制字段
+ command[17] = 0x00; //RSV 保留字段
+ command[18] = 0x02; //GCT 网关计数
+ command[19] = 0x00; //DNA 目标网络地址 00:表示本地网络 0x01~0x7F:表示远程网络
+ command[20] = 0x13; //DA1 目标节点编号 0x01~0x3E:SYSMAC LINK网络中的节点号 0x01~0x7E:YSMAC NET网络中的节点号 0xFF:广播传输
+ command[21] = UnitAddress; //DA2 目标单元地址
+ command[22] = 0x00; //SNA 源网络地址 取值及含义同DNA字段
+ command[23] = 0x0B; //SA1 源节点编号 取值及含义同DA1字段
+ command[24] = 0x00; //SA2 源单元地址 取值及含义同DA2字段
+ command[25] = 0x00; //SID Service ID 取值0x00~0xFF,产生会话的进程的唯一标识
command[26] = 0x01;
- command[27] = 0x01; //读
+ command[27] = 0x01; //Command Code 内存区域读取
command[28] = isBit ? arg.OmronFinsType.BitCode : arg.OmronFinsType.WordCode;
arg.Content.CopyTo(command, 29);
command[32] = (byte)(length / 256);
@@ -632,19 +638,19 @@ namespace IoTClient.Clients.PLC
tmp.CopyTo(command, 4);
command[11] = 0x02;
- command[16] = 0x80; //信息控制字段
- command[17] = 0x00;
- command[18] = 0x02;
- command[19] = 0x00;
- command[20] = 0x13; //0x13; //01(节点地址:Ip地址的最后一位)
- command[21] = UnitNumber; //单元号地址(传过来)
- command[22] = 0x00;
- command[23] = 0x0B; //0x0B; //01(节点地址:Ip地址的最后一位)
- command[24] = 0x00;
- command[25] = 0x00;
+ command[16] = 0x80; //ICF 信息控制字段
+ command[17] = 0x00; //RSV 保留字段
+ command[18] = 0x02; //GCT 网关计数
+ command[19] = 0x00; //DNA 目标网络地址 00:表示本地网络 0x01~0x7F:表示远程网络
+ command[20] = 0x13; //DA1 目标节点编号 0x01~0x3E:SYSMAC LINK网络中的节点号 0x01~0x7E:YSMAC NET网络中的节点号 0xFF:广播传输
+ command[21] = UnitAddress; //DA2 目标单元地址
+ command[22] = 0x00; //SNA 源网络地址 取值及含义同DNA字段
+ command[23] = 0x0B; //SA1 源节点编号 取值及含义同DA1字段
+ command[24] = 0x00; //SA2 源单元地址 取值及含义同DA2字段
+ command[25] = 0x00; //SID Service ID 取值0x00~0xFF,产生会话的进程的唯一标识
command[26] = 0x01;
- command[27] = 0x02; //写
+ command[27] = 0x02; //Command Code 内存区域写入
command[28] = isBit ? arg.OmronFinsType.BitCode : arg.OmronFinsType.WordCode;
arg.Content.CopyTo(command, 29);
command[32] = isBit ? (byte)(value.Length / 256) : (byte)(value.Length / 2 / 256);
diff --git a/IoTClient/IoTClient/IoTClient.xml b/IoTClient/IoTClient/IoTClient.xml
index 964ab3e..beea9d8 100644
--- a/IoTClient/IoTClient/IoTClient.xml
+++ b/IoTClient/IoTClient/IoTClient.xml
@@ -1157,16 +1157,26 @@
- 读取Int16
+ 读取Int16类型数据
寄存器起始地址
站号
功能码
+
- 读取UInt16
+ 读取UInt16类型数据
+
+ 寄存器起始地址
+ 站号
+ 功能码
+
+
+
+
+ 读取UInt16类型数据
寄存器起始地址
站号
@@ -1175,7 +1185,16 @@
- 读取Int32
+ 读取Int32类型数据
+
+ 寄存器起始地址
+ 站号
+ 功能码
+
+
+
+
+ 读取Int32类型数据
寄存器起始地址
站号
@@ -1184,7 +1203,16 @@
- 读取UInt32
+ 读取UInt32类型数据
+
+ 寄存器起始地址
+ 站号
+ 功能码
+
+
+
+
+ 读取UInt32类型数据
寄存器起始地址
站号
@@ -1193,7 +1221,16 @@
- 读取Int64
+ 读取Int64类型数据
+
+ 寄存器起始地址
+ 站号
+ 功能码
+
+
+
+
+ 读取Int64类型数据
寄存器起始地址
站号
@@ -1202,7 +1239,16 @@
- 读取UInt64
+ 读取UInt64类型数据
+
+ 寄存器起始地址
+ 站号
+ 功能码
+
+
+
+
+ 读取UInt64类型数据
寄存器起始地址
站号
@@ -1211,7 +1257,16 @@
- 读取Float
+ 读取Float类型数据
+
+ 寄存器起始地址
+ 站号
+ 功能码
+
+
+
+
+ 读取Float类型数据
寄存器起始地址
站号
@@ -1220,7 +1275,16 @@
- 读取Double
+ 读取Double类型数据
+
+ 寄存器起始地址
+ 站号
+ 功能码
+
+
+
+
+ 读取Double类型数据
寄存器起始地址
站号
@@ -1229,7 +1293,16 @@
- 读取线圈
+ 读取线圈类型数据
+
+ 寄存器起始地址
+ 站号
+ 功能码
+
+
+
+
+ 读取线圈类型数据
寄存器起始地址
站号
@@ -1238,11 +1311,20 @@
- 读取离散
+ 读取离散类型数据
读取地址
-
-
+ 站号
+ 功能码
+
+
+
+
+ 读取离散类型数据
+
+ 读取地址
+ 站号
+ 功能码
@@ -1254,6 +1336,15 @@
批量读取的值
+
+
+ 从批量读取的数据字节提取对应的地址数据
+
+ 批量读取的起始地址
+ 读取地址
+ 批量读取的值
+
+
从批量读取的数据字节提取对应的地址数据
@@ -1263,6 +1354,15 @@
批量读取的值
+
+
+ 从批量读取的数据字节提取对应的地址数据
+
+ 批量读取的起始地址
+ 读取地址
+ 批量读取的值
+
+
从批量读取的数据字节提取对应的地址数据
@@ -1272,6 +1372,15 @@
批量读取的值
+
+
+ 从批量读取的数据字节提取对应的地址数据
+
+ 批量读取的起始地址
+ 读取地址
+ 批量读取的值
+
+
从批量读取的数据字节提取对应的地址数据
@@ -1281,6 +1390,15 @@
批量读取的值
+
+
+ 从批量读取的数据字节提取对应的地址数据
+
+ 批量读取的起始地址
+ 读取地址
+ 批量读取的值
+
+
从批量读取的数据字节提取对应的地址数据
@@ -1290,6 +1408,15 @@
批量读取的值
+
+
+ 从批量读取的数据字节提取对应的地址数据
+
+ 批量读取的起始地址
+ 读取地址
+ 批量读取的值
+
+
从批量读取的数据字节提取对应的地址数据
@@ -1299,6 +1426,15 @@
批量读取的值
+
+
+ 从批量读取的数据字节提取对应的地址数据
+
+ 批量读取的起始地址
+ 读取地址
+ 批量读取的值
+
+
从批量读取的数据字节提取对应的地址数据
@@ -1308,6 +1444,15 @@
批量读取的值
+
+
+ 从批量读取的数据字节提取对应的地址数据
+
+ 批量读取的起始地址
+ 读取地址
+ 批量读取的值
+
+
从批量读取的数据字节提取对应的地址数据
@@ -1317,6 +1462,15 @@
批量读取的值
+
+
+ 从批量读取的数据字节提取对应的地址数据
+
+ 批量读取的起始地址
+ 读取地址
+ 批量读取的值
+
+
从批量读取的数据字节提取对应的地址数据
@@ -1326,6 +1480,15 @@
批量读取的值
+
+
+ 从批量读取的数据字节提取对应的地址数据
+
+ 批量读取的起始地址
+ 读取地址
+ 批量读取的值
+
+
从批量读取的数据字节提取对应的地址数据
@@ -1335,6 +1498,15 @@
批量读取的值
+
+
+ 从批量读取的数据字节提取对应的地址数据
+
+ 批量读取的起始地址
+ 读取地址
+ 批量读取的值
+
+
分批读取(批量读取,内部进行批量计算读取)
@@ -1348,8 +1520,8 @@
读取地址
-
-
+ 站号
+ 功能码
@@ -1357,8 +1529,8 @@
读取地址
批量读取的值
-
-
+ 站号
+ 功能码
@@ -1756,6 +1928,7 @@
欧姆龙PLC 客户端 - Beta
+ https://flat2010.github.io/2020/02/23/Omron-Fins%E5%8D%8F%E8%AE%AE/
@@ -1783,9 +1956,12 @@
-
+
- 单元号地址
+ DA2(即Destination unit address,目标单元地址)
+ 0x00:PC(CPU)
+ 0xFE: SYSMAC NET Link Unit or SYSMAC LINK Unit connected to network;
+ 0x10~0x1F:CPU总线单元 ,其值等于10 + 单元号(前端面板中配置的单元号)
diff --git a/README.md b/README.md
index 3f4aeca..fb8268d 100644
--- a/README.md
+++ b/README.md
@@ -22,11 +22,32 @@ ModBusTcpClient client = new ModBusTcpClient("127.0.0.1", 502);
//2、写操作 - 参数依次是:地址 、值 、站号 、功能码
client.Write("4", (short)33, 2, 16);
-client.Write("4", (short)3344, 2, 16);
+
+//2.1、【注意】写入数据的时候需要明确数据类型
+client.Write("0", (short)33, 2, 16); //写入的是short类型数值
+client.Write("4", (ushort)33, 2, 16); //写入的是ushort类型数值
+client.Write("8", (int)33, 2, 16); //写入的是int类型数值
+client.Write("12", (uint)33, 2, 16); //写入的是uint类型数值
+client.Write("16", (long)33, 2, 16); //写入的是long类型数值
+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); //写入的是线圈类型数值
//3、读操作 - 参数依次是:地址 、站号 、功能码
var value = client.ReadInt16("4", 2, 3).Value;
-var value2 = client.ReadInt32("4", 2, 3).Value;
+
+//3.1、其他类型数据读取
+client.ReadInt16("0", stationNumber, 3); //short类型数据读取
+client.ReadUInt16("4", stationNumber, 3); //ushort类型数据读取
+client.ReadInt32("8", stationNumber, 3); //int类型数据读取
+client.ReadUInt32("12", stationNumber, 3); //uint类型数据读取
+client.ReadInt64("16", stationNumber, 3); //long类型数据读取
+client.ReadUInt64("20", stationNumber, 3); //ulong类型数据读取
+client.ReadFloat("24", stationNumber, 3); //float类型数据读取
+client.ReadDouble("28", stationNumber, 3); //double类型数据读取
+client.ReadCoil("32", stationNumber, 1); //线圈类型数据读取
+client.ReadDiscrete("32", stationNumber, 2);//离散类型数据读取
//4、如果没有主动Open,则会每次读写操作的时候自动打开自动和关闭连接,这样会使读写效率大大减低。所以建议手动Open和Close。
client.Open();
@@ -74,6 +95,8 @@ var result = client.BatchRead(list);
ModBusTcpClient client = new ModBusTcpClient("127.0.0.1", 502, 1500, EndianFormat.ABCD);
```
+### ModBusTcp更多使用方式,请参考[单元测试](https://github.com/zhaopeiym/IoTClient/blob/master/IoTClient.Tests/Modbus_Tests/ModBusTcpClient_tests.cs)
+
## ModBusRtu读写操作
```
//实例化客户端 - [COM端口名称,波特率,数据位,停止位,奇偶校验]
@@ -82,6 +105,24 @@ ModBusRtuClient client = new ModBusRtuClient("COM3", 9600, 8, StopBits.One, Pari
//其他读写操作和ModBusTcpClient的读写操作一致
```
+## ModBusAscii读写操作
+```
+//实例化客户端 - [COM端口名称,波特率,数据位,停止位,奇偶校验]
+ModbusAsciiClient client = new ModbusAsciiClient("COM3", 9600, 8, StopBits.One, Parity.None);
+
+//其他读写操作和ModBusTcpClient的读写操作一致
+```
+
+## ModbusRtuOverTcp读写操作
+```
+//串口透传 即:用Tcp的方式发送Rtu格式报文
+
+//实例化客户端 - IP、端口、超时时间、大小端设置
+ModbusRtuOverTcpClient client = new ModbusRtuOverTcpClient("127.0.0.1", 502, 1500, EndianFormat.ABCD);
+
+//其他读写操作和ModBusTcpClient的读写操作一致
+```
+
## SiemensClient(西门子)读写操作
```
//1、实例化客户端 - 输入正确的IP和端口