Alter Description.

This commit is contained in:
luosheng
2023-02-11 10:26:31 +08:00
parent 371ee48a7b
commit 86e084f814
9 changed files with 68 additions and 330 deletions

View File

@@ -7,14 +7,14 @@
<PackageId>Modbus.Net.Modbus</PackageId>
<Version>1.4.1</Version>
<Authors>Chris L.(Luo Sheng)</Authors>
<Company>Hangzhou Delian IoT Science Technology Co.,Ltd.</Company>
<Company>Hangzhou Delian Science Technology Co.,Ltd.</Company>
<Product>Modbus.Net.Modbus</Product>
<Description>Modbus.Net Modbus Implementation</Description>
<Copyright>Copyright 2017 Hangzhou Delian IoT Science Technology Co.,Ltd.</Copyright>
<Copyright>Copyright 2023 Hangzhou Delian Science Technology Co.,Ltd.</Copyright>
<PackageProjectUrl>https://github.com/parallelbgls/Modbus.Net/tree/master/Modbus.Net/Modbus.Net.Modbus</PackageProjectUrl>
<RepositoryUrl>https://github.com/parallelbgls/Modbus.Net</RepositoryUrl>
<RepositoryType>git</RepositoryType>
<PackageTags>hardware communicate protocal modbus Delian</PackageTags>
<PackageTags>hardware communicate protocol modbus Delian</PackageTags>
<PackageRequireLicenseAcceptance>False</PackageRequireLicenseAcceptance>
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
<IncludeSymbols>True</IncludeSymbols>

View File

@@ -7,13 +7,13 @@
<PackageId>Modbus.Net.Siemens</PackageId>
<Version>1.4.1</Version>
<Authors>Chris L.(Luo Sheng)</Authors>
<Company>Hangzhou Delian IoT Science Technology Co.,Ltd.</Company>
<Company>Hangzhou Delian Science Technology Co.,Ltd.</Company>
<Description>Modbus.Net Siemens Profinet Implementation</Description>
<Copyright>Copyright 2017 Hangzhou Delian IoT Science Technology Co.,Ltd.</Copyright>
<Copyright>Copyright 2023 Hangzhou Delian Science Technology Co.,Ltd.</Copyright>
<PackageProjectUrl>https://github.com/parallelbgls/Modbus.Net/tree/master/Modbus.Net/Modbus.Net.Siemens</PackageProjectUrl>
<RepositoryUrl>https://github.com/parallelbgls/Modbus.Net</RepositoryUrl>
<RepositoryType>git</RepositoryType>
<PackageTags>hardware communicate protocal Siemens profinet Delian</PackageTags>
<PackageTags>hardware communicate protocol Siemens profinet Delian</PackageTags>
<PackageRequireLicenseAcceptance>False</PackageRequireLicenseAcceptance>
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
<IncludeSymbols>True</IncludeSymbols>

View File

@@ -23,27 +23,27 @@ namespace Modbus.Net
/// <summary>
/// 将协议坐标变为字节坐标
/// </summary>
/// <param name="protocalAddress">协议坐标地址</param>
/// <param name="protocolAddress">协议坐标地址</param>
/// <param name="startAddress">起始地址</param>
/// <param name="byteLength">协议坐标单个地址的字节长度</param>
/// <returns></returns>
public static double MapProtocolCoordinateToAbstractCoordinate(double protocalAddress, int startAddress,
public static double MapProtocolCoordinateToAbstractCoordinate(double protocolAddress, int startAddress,
double byteLength)
{
return (protocalAddress - startAddress) * byteLength;
return (protocolAddress - startAddress) * byteLength;
}
/// <summary>
/// 将协议获取数变为字节获取数
/// </summary>
/// <param name="protocalGetCount">协议坐标获取个数</param>
/// <param name="protocolGetCount">协议坐标获取个数</param>
/// <param name="areaLength">协议坐标区域与字节之间的防缩倍数</param>
/// <param name="byteLength">协议坐标单个地址的字节长度</param>
/// <returns></returns>
public static double MapProtocolGetCountToAbstractByteCount(double protocalGetCount, double areaLength,
public static double MapProtocolGetCountToAbstractByteCount(double protocolGetCount, double areaLength,
double byteLength)
{
return protocalGetCount * areaLength + byteLength;
return protocolGetCount * areaLength + byteLength;
}
/// <summary>
@@ -72,14 +72,14 @@ namespace Modbus.Net
/// <summary>
/// 获取协议坐标下一个数据的位置
/// </summary>
/// <param name="protocalAddress">协议坐标地址</param>
/// <param name="protocolAddress">协议坐标地址</param>
/// <param name="nextPositionBetweenType">间隔的数据类型</param>
/// <param name="byteLength">协议坐标单个地址的字节长度</param>
/// <returns></returns>
public static double GetProtocolCoordinateNextPosition(double protocalAddress, Type nextPositionBetweenType,
public static double GetProtocolCoordinateNextPosition(double protocolAddress, Type nextPositionBetweenType,
double byteLength)
{
return protocalAddress +
return protocolAddress +
BigEndianValueHelper.Instance.ByteLength[nextPositionBetweenType.FullName] / byteLength;
}

View File

@@ -8,12 +8,12 @@
<Version>1.4.1</Version>
<Product>Modbus.Net</Product>
<Authors>Chris L.(Luo Sheng)</Authors>
<Company>Hangzhou Delian IoT Science Technology Co.,Ltd.</Company>
<Company>Hangzhou Delian Science Technology Co.,Ltd.</Company>
<PackageProjectUrl>https://github.com/parallelbgls/Modbus.Net/tree/master/Modbus.Net</PackageProjectUrl>
<RepositoryUrl>https://github.com/parallelbgls/Modbus.Net/</RepositoryUrl>
<Description>High extensible hardware communication implementation platform.</Description>
<Copyright>Copyright 2017 Hangzhou Delian IoT Science Technology Co.,Ltd.</Copyright>
<PackageTags>hardware communicate protocal Delian</PackageTags>
<Copyright>Copyright 2023 Hangzhou Delian Science Technology Co.,Ltd.</Copyright>
<PackageTags>hardware communicate protocol Delian</PackageTags>
<RepositoryType>git</RepositoryType>
<PackageRequireLicenseAcceptance>False</PackageRequireLicenseAcceptance>
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>

View File

@@ -103,25 +103,25 @@ namespace Modbus.Net
{
get
{
var protocalName = type.FullName;
TProtocolUnit protocalUnitReturn = null;
var protocolName = type.FullName;
TProtocolUnit protocolUnitReturn = null;
lock (Protocols)
{
if (Protocols.ContainsKey(protocalName))
if (Protocols.ContainsKey(protocolName))
{
protocalUnitReturn = Protocols[protocalName];
protocolUnitReturn = Protocols[protocolName];
}
else
{
//自动寻找存在的协议并将其加载
if (!(Activator.CreateInstance(type.GetTypeInfo().Assembly
.GetType(protocalName)) is TProtocolUnit protocalUnit))
.GetType(protocolName)) is TProtocolUnit protocolUnit))
throw new InvalidCastException($"No ProtocolUnit {nameof(TProtocolUnit)} implemented");
protocalUnit.Endian = Endian;
Register(protocalUnit);
protocolUnit.Endian = Endian;
Register(protocolUnit);
}
}
return protocalUnitReturn ?? Protocols[protocalName];
return protocolUnitReturn ?? Protocols[protocolName];
}
}

View File

@@ -13,8 +13,8 @@ namespace Modbus.Net
/// <summary>
/// 构造函数
/// </summary>
/// <param name="protocalLinker">连接器</param>
public PipeUnit(IProtocolLinker<byte[], byte[]> protocalLinker) : base(protocalLinker)
/// <param name="protocolLinker">连接器</param>
public PipeUnit(IProtocolLinker<byte[], byte[]> protocolLinker) : base(protocolLinker)
{
}
@@ -22,12 +22,12 @@ namespace Modbus.Net
/// <summary>
/// 构造函数
/// </summary>
/// <param name="protocalLinker">连接器</param>
/// <param name="protocalUnit">协议单元</param>
/// <param name="protocolLinker">连接器</param>
/// <param name="protocolUnit">协议单元</param>
/// <param name="parameters">传递给输入结构的参数</param>
/// <param name="success">上次的管道是否成功执行</param>
protected PipeUnit(IProtocolLinker<byte[], byte[]> protocalLinker, ProtocolUnit protocalUnit, byte[] parameters,
bool success) : base(protocalLinker, protocalUnit, parameters, success)
protected PipeUnit(IProtocolLinker<byte[], byte[]> protocolLinker, ProtocolUnit protocolUnit, byte[] parameters,
bool success) : base(protocolLinker, protocolUnit, parameters, success)
{
}
@@ -93,8 +93,8 @@ namespace Modbus.Net
/// <summary>
/// 构造函数
/// </summary>
/// <param name="protocalLinker">连接器</param>
public PipeUnit(TProtocolLinker protocalLinker) : this(protocalLinker, null, null, true)
/// <param name="protocolLinker">连接器</param>
public PipeUnit(TProtocolLinker protocolLinker) : this(protocolLinker, null, null, true)
{
}
@@ -102,14 +102,14 @@ namespace Modbus.Net
/// <summary>
/// 构造函数
/// </summary>
/// <param name="protocalLinker">连接器</param>
/// <param name="protocalUnit">协议单元</param>
/// <param name="protocolLinker">连接器</param>
/// <param name="protocolUnit">协议单元</param>
/// <param name="parameters">输入参数</param>
/// <param name="success">上一次管道结果是否成功</param>
protected PipeUnit(TProtocolLinker protocalLinker, TProtocolUnit protocalUnit, TParamOut parameters, bool success)
protected PipeUnit(TProtocolLinker protocolLinker, TProtocolUnit protocolUnit, TParamOut parameters, bool success)
{
ProtocolLinker = protocalLinker;
ProtocolUnit = protocalUnit;
ProtocolLinker = protocolLinker;
ProtocolUnit = protocolUnit;
ReturnParams = parameters;
Success = success;
}

View File

@@ -5,6 +5,7 @@ Modbus.Net
An hardware communication Library written by C#.
Table of Content:
* [License Description](#license)
* [Features](#features)
* [Usage](#usage)
* [Architecture](#architecture)
@@ -13,34 +14,26 @@ Table of Content:
* [Implement](#implement)
* [Addition](#addition)
## <a name="license"></a> License Description
This project uses MIT license. This means you can alter any codes, use in your project without any declaration.
## <a name="features"></a> Features
* A open platform that you can easy to extend a industrial communication protocal.
* Modbus Tcp protocal.
* Siemens Tcp protocal (acturally it is the same as Profinet)
* OPC DA protocal.
* A open platform that you can easily extend a industrial communication protocol.
* Modbus Tcp protocol.
* Siemens Tcp protocol (acturally it is the same as Profinet)
* All communications could be asynchronized.
* A task manager that you can easily manage multiple connections.
* .NET Framework 4.5 and Visual Studio 2017 support.
## <a name="usage"></a> Usage
### Samples:
There are four samples in the project. All sample project recommand running in Siemens 200 PLC.
PLC Program could be opened by Siemens Portal V13 (Step 7 V13).
Modbus TCP connection and Siemens Ethenet Connection are supported at the same time.
* TripleAdd -- Add three numbers in PLC.
* TaskManager -- Sample usage of TaskManager.
* AnyType -- Get any type in registers.
* CrossLamp -- A sample singal lamp controller.
* .NET 6.0 support.
## <a name="architecture"></a> Architecture
### Controller
Controller implements the basic message control methods, like FIFO.
### Connector
Connector implements the basic connecting methods, like Socket, Com and SignalR.
Connector implements the basic connecting methods, like Socket, Com.
### ProtocolLinker
@@ -52,7 +45,7 @@ Some Protocol has the same head or tail in the same connection way, but differen
### ProtocolUnit
Format and deformat the protocal message between the structual class and bytes array.
Format and deformat the protocol message between the structual class and bytes array.
### ValueHelper
@@ -60,7 +53,7 @@ Help change the value between number and bytes, or number array to bytes array.
### Protocol
Manage all protocals and implement a lazy loading method.
Manage all protocols and implement a lazy loading method.
### Utility
@@ -82,71 +75,8 @@ Translate address from string to definite address.
Combine duplicated addresses to organized addresses, each organized addresses communicate once to a device.
### TaskManager
The highest api that you can manage many PLC links and all links are async so there are no block in all connections.
## <a name="quick_start"></a> Quick Start.
The fastest way you can write is to use TaskManager. TaskManager Project is a good example.
```C#
List<AddressUnit> addressUnits = new List<AddressUnit>
{
new AddressUnit() {Id = "0", Area = "V", Address = 1, CommunicationTag = "D1", DataType = typeof (ushort), Zoom = 1},
new AddressUnit() {Id = "1", Area = "V", Address = 3, CommunicationTag = "D2", DataType = typeof (float), Zoom = 1}
};
TaskManager task = new TaskManager(10, true);
task.AddMachine(new SiemensMachine(SiemensType.Tcp, "192.168.3.11", SiemensMachineModel.S7_300, addressUnits,
true, 2, 0));
task.InvokeTimerAll(new TaskItemGetData(returnValues =>
{
if (returnValues.ReturnValues != null)
{
lock (values)
{
var unitValues = from val in returnValues.ReturnValues
select
new Tuple<AddressUnit, double?>(
addressUnits.FirstOrDefault(p => p.CommunicationTag == val.Key), val.Value.PlcValue);
values = from unitValue in unitValues
select
new TaskViewModel()
{
Id = unitValue.Item1.Id,
Name = unitValue.Item1.Name,
Address = unitValue.Item1.Address.ToString(),
Value = unitValue.Item2 ?? 0,
Type = unitValue.Item1.DataType.Name
};
}
}
else
{
Console.WriteLine($"ip {returnValues.MachineId} not return value");
}
}, MachineGetDataType.CommunicationTag, 5000, 60000));
```
Here are the details to use the TaskManager.
1. Initialize the task manager.
Three arguments are: the max tasks you can run in a same time; How long did the next send message call happens(milliseconds); and you should keep the connection when a single message called complete.
2. Add the addresses that you want to communicate to PLC. Area are defined in AddressTranslator in each type of communiction.
Basically you can write only Id, Area, Address, CommunicationTag, DataType and Zoom, and it should work. And there are other fields that you can use.
More important, you can extend and implement your own field in UnitExtend in every AddressUnit, and it will return in return event.
3. Add a machine to TaskManager.
Add a machine like siemens machine to the task manager.
4. Add a TaskItem for one machine or all Machines.
Modbus.Net implement TaskItemGetDatas and TaskItemSetDatas as the default.
##<a name="tutorial"></a> Tutorial
This platform has three level APIs that you could use: Low level API called "BaseUtility"; Middle level API called "BaseMachine"; High level API called "TaskManager".
This platform has three level APIs that you could use: Low level API called "BaseUtility"; Middle level API called "BaseMachine"
### Utility
IUtilityProperty is a low level api, in this level you can get or set data only by byte array or object array. Here is an example.
@@ -292,107 +222,14 @@ machine.SetDatas has four types. It is referenced as the first parameter.
3. MachineSetDataType.Id: the key of the dictionary of the second paramenter is ID.
4. MachineSetDataType.Name: the key of the dictionary of the second paramenter is name.
### TaskManager
TaskManager is a high level api that you can manage and control many machines together. Remenber if you want to use this class, all communications must be asyncronized.
Sample of TaskManager calls like this.
```C#
TaskManager task = new TaskManager(10, 2000, true);
List<AddressUnit> addressUnits = new List<AddressUnit>
{
new AddressUnit() {Id = 0, Area = "V", Address = 1, CommunicationTag = "D1", DataType = typeof (ushort), Zoom = 1},
new AddressUnit() {Id = 1, Area = "V", Address = 3, CommunicationTag = "D2", DataType = typeof (float), Zoom = 1}
};
task.AddMachine(new SiemensMachine(SiemensType.Tcp, "192.168.3.11",SiemensMachineModel.S7_300, addressUnits, true));
task.InvokeTimerAll(new TaskItemGetData(returnValues =>
{
if (returnValues.ReturnValues != null)
{
lock (values)
{
var unitValues = from val in returnValues.ReturnValues
select
new Tuple<AddressUnit, double?>(
addressUnits.FirstOrDefault(p => p.CommunicationTag == val.Key), val.Value.PlcValue);
values = from unitValue in unitValues
select
new TaskViewModel()
{
Id = unitValue.Item1.Id,
Name = unitValue.Item1.Name,
Address = unitValue.Item1.Address.ToString(),
Value = unitValue.Item2 ?? 0,
Type = unitValue.Item1.DataType.Name
};
}
}
else
{
Console.WriteLine($"ip {returnValues.MachineId} not return value");
}
}, MachineGetDataType.CommunicationTag, 5000, 60000));
```
To use the TaskManager, use following steps.
1.New A TaskManager instance.
```C#
TaskManager task = new TaskManager(10, 2000, true);
```
2.Add a machine to TaskManager.
```C#
List<AddressUnit> addressUnits = new List<AddressUnit>
{
new AddressUnit() {Id = 0, Area = "V", Address = 1, CommunicationTag = "D1", DataType = typeof (ushort), Zoom = 1},
new AddressUnit() {Id = 1, Area = "V", Address = 3, CommunicationTag = "D2", DataType = typeof (float), Zoom = 1}
};
task.AddMachine(new SiemensMachine(SiemensType.Tcp, "192.168.3.11", SiemensMachineModel.S7_300, addressUnits, true));
```
3.Add a get value cycling task. You can handle return values with your own code (ReturnValue event before 1.3.2).
```C#
task.InvokeTimerAll(new TaskItemGetData(returnValues =>
{
if (returnValues.ReturnValues != null)
{
lock (values)
{
var unitValues = from val in returnValues.ReturnValues
select
new Tuple<AddressUnit, double?>(
addressUnits.FirstOrDefault(p => p.CommunicationTag == val.Key), val.Value.PlcValue);
values = from unitValue in unitValues
select
new TaskViewModel()
{
Id = unitValue.Item1.Id,
Name = unitValue.Item1.Name,
Address = unitValue.Item1.Address.ToString(),
Value = unitValue.Item2 ?? 0,
Type = unitValue.Item1.DataType.Name
};
}
}
else
{
Console.WriteLine($"ip {returnValues.MachineId} not return value");
}
}, MachineGetDataType.CommunicationTag, 5000, 60000));
```
5.And don't forget that there is also a SetDatasAsync Api in the TaskManager.
```C#
public async Task<bool> SetDatasAsync(string connectionToken, MachineSetDataType setDataType, Dictionary<string, double> values)
```
##<a name="implement"></a> Implementing Your Own Protocol
The main target of Modbus.Net is building a high extensable hardware communication protocal, so we allow everyone to extend the protocal.
The main target of Modbus.Net is building a high extensable hardware communication protocol, so we allow everyone to extend the protocol.
To extend Modbus.Net, first of all ValueHelper.cs in Modbus.Net is a really powerful tool that you can use to modify values in byte array.There are two ValueHelpers: ValueHelper(Little Endian) and BigEndianValueHelper(Big Endian). Remember using the correct one.
In this tutorial I will use Modbus.Net.Modbus to tell you how to implement your own protocal.
In this tutorial I will use Modbus.Net.Modbus to tell you how to implement your own protocol.
You should follow the following steps to implement your own protocal.
You should follow the following steps to implement your own protocol.
1.Implement Protocol. (ModbusProtocol.cs, ModbusTcpProtocol.cs)
First: Extend BaseProtocol to ModbusProtocol.
@@ -400,7 +237,7 @@ First: Extend BaseProtocol to ModbusProtocol.
public abstract class ModbusProtocol : BaseProtocol
public class ModbusTcpProtocol : ModbusProtocol
```
"abstract" keyword is optional because if user can use this protocal don't write abstract.
"abstract" keyword is optional because if user can use this protocol don't write abstract.
Second: Extend ProtocolUnit, IInputStruct and IOutputStruct.
```C#
@@ -424,7 +261,7 @@ public class ReadDataModbusProtocol : ProtocolUnit
}
```
There is another attribute called SpecialProtocolUnitAttribute.
If you add SpecialProtocolUnitAttribute to ProtocolUnit, then the protocal will not run BytesExtend and BytesDecact.
If you add SpecialProtocolUnitAttribute to ProtocolUnit, then the protocol will not run BytesExtend and BytesDecact.
```C#
[SpecialProtocolUnit]
internal class CreateReferenceSiemensProtocol : ProtocolUnit
@@ -548,9 +385,9 @@ First of all, there are two types of coordinates in Modbus.Net Address System -
Here is an example of the differences between them:
In Register of Modbus, the minimum type is short, but Modbus.Net use type of byte to show the result. If you want to get value from 400003 in protocal coordinate, you actually get 5th and 6th byte value in abstract coordinate.
In Register of Modbus, the minimum type is short, but Modbus.Net use type of byte to show the result. If you want to get value from 400003 in protocol coordinate, you actually get 5th and 6th byte value in abstract coordinate.
Version 1.0 and 1.1 used abstract coordinate so you need to convert the address. But fortunatly after 1.2, AddressUnit uses Protocol Coordinate so that you donnot need the convert the address descripted by modbus protocal itself, but this means if you want to get a bit or byte value in modbus, you need to use the subpos system.
Version 1.0 and 1.1 used abstract coordinate so you need to convert the address. But fortunatly after 1.2, AddressUnit uses Protocol Coordinate so that you donnot need the convert the address descripted by modbus protocol itself, but this means if you want to get a bit or byte value in modbus, you need to use the subpos system.
For example if you want the get a value from the 6th byte in Hold Register. In traditional modbus you can only get 400003 of 2 bytes and get the 2nd byte from it. But in Modbus.Net there is an easy way to get it.
```

110
README.md
View File

@@ -1,11 +1,9 @@
Modbus.Net Overview
===================
* [Teambition Project](https://www.teambition.com/project/573860b0f668c69e61d38a84/tasks)
Overview
-------------------
Modbus.Net is an open hardware communication platform written in C# 7.0.
Modbus.Net is an open hardware communication platform.
You can focus on the protocol itself and the platform can automatically create a full asynchronous or synchronous communication library.
@@ -17,111 +15,13 @@ The real Modbus Implementation has been moved to [Modbus.Net.Modbus]( https://ww
There is also [Modbus.Net.Siemens]( https://www.nuget.org/packages/Modbus.Net.Siemens) that can communicate with Siemens S7-200, S7-200 Smart, S7-300, S7-400, S7-1200 and S7-1500 using PPI or TCP/IP.
[Modbus.Net.OPC]( https://www.nuget.org/packages/Modbus.Net.OPC) Implements OPC DA and OPC UA protocol.
Supported Platforms
-------------------
* Visual Studio 2017
* .NET Framework 4.5
* .NET Standard 2.0
* Visual Studio 2022
* .NET 6.0
Thanks
-------------------
Resharper -- Offers Modbus.Net team community license.
RoadMap
-------------------
### Version 1.2.0
* Modbus ASCII Support (Complete)
* Siemens PPI Support (Complete)
* OPC Write Data (Complete)
* Get and set bit value (Complete)
* Unit test (Complete)
* New Document (Complete)
* New Samples (Complete)
### Version 1.2.2
* Address Utility (Complete)
* More functions in TaskManager (Complete)
* More interfaces (Complete)
### Version 1.2.3
* Endian Problem Fix (Complete)
* Name mode in TaskManager (Complete)
### Version 1.2.4
* OPC UA Support (Complete)
* OPC Regex comparer for tags (Complete)
### Version 1.3.0
* .NET Core Support (Complete)
* Fix a bug in BaseMachine (Complete)
### Version 1.3.1
* InputStruct -> IInputStruct, OutputStruct -> IOutputStruct (Complete)
* Generic Method For ProtocalUnit (Complete)
### Version 1.3.2
* Add Interface IMachineMethod and IUtilityMethod. Utiltiy and Machine can extend function using interface (Complete)
### Version 1.3.3
* TaskManager Remake (Complete)
### Version 1.3.4
* A Serial Port now can connect to multiple machines using same protocol with different slave address (Complete)
### Version 1.3.5
* New log system using Serilog (Complete)
### Version 1.3.6
* Add gereric Type for BaseConnector, now protocol developer can pass any type to BaseConnector not only byte[] (Complete)
* Add more gereric types in Modbus.Net to support this function (Complete)
* Add more interfaces to make them completed in Modbus.Net (Complete)
* Support this function in Modbus.Net.OPC (Complete)
### Version 1.3.7
* AddressCombiner need to add maximum length now. Combiner will consider the maximum length when combining addresses (Complete)
### Version 1.3.8
* Change Resx to appsettings.json, now you can set default params there (Complete - CORE ONLY)
* Change ISpecialProtocalUnit to SpecialProtocalUnitAttribute (Complete)
### Version 1.3.9
* Modbus Single Write for Coil and Reg (05 and 06) (Complete)
* Fix OPC tag combine problem (Complete)
### 1.3.X Other
* Github wiki Document Chinese (Complete)
* Github wiki Document English (Complete)
### Version 1.3.10
* Update to .Net Standard 2.0 (Complete)
### Version 1.4.0
* New Protocol Pipeline System (Complete)
### Version 1.4.1
* BaseController (Complete)
* New ComConnector (Complete)
* New TcpConnector (Complete)
* New UdpConnector (Complete)
* Serial Port Connection with Multiple Master Station (Complete)
### Version 1.4.2
* Machine Builder (In Progress)
* Architecture rebuild (Almost complete)
### Version 1.5.X
* PPI Remake (In Progress)
* Siemens MPI Support (In Progress)
* Siemens MultiStation PPI Support (In Progress)
* Passive Connector and Controller (In Progress)
### Version 1.6.X
* English comment (In Progress)
* ValueHelper remake to interface, users can add their own value translate function (In Progress)
* New Zoom (In Progress)
### Version 2.0.0
* Rename to Transport.Net (In Progress)
Quartz - Job Scheduler
Serilog - Logging

View File

@@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Threading;
using Modbus.Net.Modbus;
using Modbus.Net.Interface;
using Serilog;
namespace Modbus.Net.PersistedTests