2017-04-26 update 1 Add extend interface for Machine and Utility.

This commit is contained in:
parallelbgls
2017-04-26 15:32:35 +08:00
parent 01d55c4337
commit 7d3ed1dcd7
14 changed files with 352 additions and 58 deletions

View File

@@ -5,7 +5,7 @@
<AssemblyName>Modbus.Net</AssemblyName>
<RootNamespace>Modbus.Net</RootNamespace>
<PackageId>Modbus.Net.Core</PackageId>
<Version>1.3.1</Version>
<Version>1.3.2</Version>
<Product>Modbus.Net</Product>
<Authors>Chris L.(Luo Sheng)</Authors>
<Company>Hangzhou Delian IoT Science Technology Co.,Ltd.</Company>
@@ -20,6 +20,10 @@
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<DocumentationFile>bin\Debug\netstandard1.3\Modbus.Net.xml</DocumentationFile>
</PropertyGroup>
<ItemGroup>
<Compile Include="..\src\Base.Common\AddressCombiner.cs" Link="AddressCombiner.cs" />
<Compile Include="..\src\Base.Common\AddressFormater.cs" Link="AddressFormater.cs" />
@@ -42,6 +46,8 @@
<Compile Include="..\src\Base.Common\TcpConnector.cs" Link="TcpConnector.cs" />
<Compile Include="..\src\Base.Common\TcpProtocalLinker.cs" Link="TcpProtocalLinker.cs" />
<Compile Include="..\src\Base.Common\ValueHelper.cs" Link="ValueHelper.cs" />
<Compile Include="..\src\Base.Common\IUtilityMethod.cs" Link="IUtilityMethod.cs" />
<Compile Include="..\src\Base.Common\IMachineMethod.cs" Link="IMachineMethod.cs" />
</ItemGroup>
<ItemGroup>

View File

@@ -5,7 +5,7 @@
<AssemblyName>Modbus.Net.Modbus</AssemblyName>
<RootNamespace>Modbus.Net.Modbus</RootNamespace>
<PackageId>Modbus.Net.Modbus</PackageId>
<Version>1.3.1</Version>
<Version>1.3.2</Version>
<Authors>Chris L.(Luo Sheng)</Authors>
<Company>Hangzhou Delian IoT Science Technology Co.,Ltd.</Company>
<Product>Modbus.Net.Modbus</Product>
@@ -19,6 +19,10 @@
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<DocumentationFile>bin\Debug\net45\Modbus.Net.Modbus.xml</DocumentationFile>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\ModBus.Net\Modbus.Net.csproj" />
</ItemGroup>

View File

@@ -1,4 +1,5 @@
using System.Threading.Tasks;
using System;
using System.Threading.Tasks;
namespace Modbus.Net.Modbus
{
@@ -26,7 +27,7 @@ namespace Modbus.Net.Modbus
/// <summary>
/// Modbus基础Api入口
/// </summary>
public class ModbusUtility : BaseUtility
public class ModbusUtility : BaseUtility, IUtilityTime
{
/// <summary>
/// Modbus协议类型
@@ -168,19 +169,18 @@ namespace Modbus.Net.Modbus
}
}
/*
/// <summary>
/// 读时间
/// </summary>
/// <returns>设备的时间</returns>
public override DateTime GetTime()
public async Task<DateTime> GetTimeAsync()
{
try
{
var inputStruct = new GetSystemTimeModbusInputStruct(SlaveAddress);
var outputStruct =
Wrapper.SendReceive<GetSystemTimeModbusOutputStruct>(Wrapper[typeof(GetSystemTimeModbusProtocal)], inputStruct);
return outputStruct?.Time;
await Wrapper.SendReceiveAsync<GetSystemTimeModbusOutputStruct>(Wrapper[typeof(GetSystemTimeModbusProtocal)], inputStruct);
return outputStruct?.Time ?? DateTime.MinValue;
}
catch (Exception)
{
@@ -193,13 +193,13 @@ namespace Modbus.Net.Modbus
/// </summary>
/// <param name="setTime">需要写入的时间</param>
/// <returns>写入是否成功</returns>
public override bool SetTime(DateTime setTime)
public async Task<bool> SetTimeAsync(DateTime setTime)
{
try
{
var inputStruct = new SetSystemTimeModbusInputStruct(SlaveAddress, setTime);
var outputStruct =
Wrapper.SendReceive<SetSystemTimeModbusOutputStruct>(Wrapper[typeof(SetSystemTimeModbusProtocal)], inputStruct);
await Wrapper.SendReceiveAsync<SetSystemTimeModbusOutputStruct>(Wrapper[typeof(SetSystemTimeModbusProtocal)], inputStruct);
return outputStruct?.WriteCount > 0;
}
catch (Exception)
@@ -207,6 +207,5 @@ namespace Modbus.Net.Modbus
return false;
}
}
*/
}
}

View File

@@ -5,7 +5,7 @@
<AssemblyName>Modbus.Net.OPC</AssemblyName>
<RootNamespace>Modbus.Net.OPC</RootNamespace>
<PackageId>Modbus.Net.OPC</PackageId>
<Version>1.3.1</Version>
<Version>1.3.2</Version>
<Authors>Chris L.(Luo Sheng)</Authors>
<Company>Hangzhou Delian IoT Science Technology Co.,Ltd.</Company>
<Description>Modbus.Net OPC Implementation</Description>
@@ -19,6 +19,10 @@
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<DocumentationFile>bin\Debug\net45\Modbus.Net.OPC.xml</DocumentationFile>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="H.Opc" Version="0.8.1" />
</ItemGroup>

View File

@@ -5,7 +5,7 @@
<AssemblyName>Modbus.Net.Siemens</AssemblyName>
<RootNamespace>Modbus.Net.Siemens</RootNamespace>
<PackageId>Modbus.Net.Siemens</PackageId>
<Version>1.3.1</Version>
<Version>1.3.2</Version>
<Authors>Chris L.(Luo Sheng)</Authors>
<Company>Hangzhou Delian IoT Science Technology Co.,Ltd.</Company>
<Description>Modbus.Net Siemens Profinet Implementation</Description>
@@ -18,6 +18,10 @@
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<DocumentationFile>bin\Debug\net45\Modbus.Net.Siemens.xml</DocumentationFile>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\ModBus.Net\Modbus.Net.csproj" />
</ItemGroup>

View File

@@ -140,10 +140,10 @@ namespace Modbus.Net.Siemens
break;
}
//MPI
//case SiemensType.Mpi:
// {
// throw new NotImplementedException();
// }
case SiemensType.Mpi:
{
throw new NotImplementedException();
}
//Ethenet
case SiemensType.Tcp:
{
@@ -216,17 +216,5 @@ namespace Modbus.Net.Siemens
return false;
}
}
/*
public override DateTime GetTime(byte slaveAddress)
{
throw new NotImplementedException();
}
public override bool SetTime(byte slaveAddress, DateTime setTime)
{
throw new NotImplementedException();
}
*/
}
}

View File

@@ -5,7 +5,7 @@
<AssemblyName>Modbus.Net</AssemblyName>
<RootNamespace>Modbus.Net</RootNamespace>
<PackageId>Modbus.Net</PackageId>
<Version>1.3.1</Version>
<Version>1.3.2</Version>
<Product>Modbus.Net</Product>
<Authors>Chris L.(Luo Sheng)</Authors>
<Company>Hangzhou Delian IoT Science Technology Co.,Ltd.</Company>
@@ -19,6 +19,10 @@
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<DocumentationFile>bin\Debug\net45\Modbus.Net.xml</DocumentationFile>
</PropertyGroup>
<ItemGroup>
<Compile Include="..\src\Base.Common\AddressCombiner.cs" Link="AddressCombiner.cs" />
<Compile Include="..\src\Base.Common\AddressFormater.cs" Link="AddressFormater.cs" />
@@ -41,6 +45,8 @@
<Compile Include="..\src\Base.Common\TcpConnector.cs" Link="TcpConnector.cs" />
<Compile Include="..\src\Base.Common\TcpProtocalLinker.cs" Link="TcpProtocalLinker.cs" />
<Compile Include="..\src\Base.Common\ValueHelper.cs" Link="ValueHelper.cs" />
<Compile Include="..\src\Base.Common\IUtilityMethod.cs" Link="IUtilityMethod.cs" />
<Compile Include="..\src\Base.Common\IMachineMethod.cs" Link="IMachineMethod.cs" />
</ItemGroup>
<ItemGroup>

View File

@@ -1,10 +1,37 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
namespace Modbus.Net
{
/// <summary>
/// 读写设备值的方式
/// </summary>
public enum MachineDataType
{
/// <summary>
/// 地址
/// </summary>
Address,
/// <summary>
/// 通讯标识
/// </summary>
CommunicationTag,
/// <summary>
/// 名称
/// </summary>
Name,
/// <summary>
/// Id
/// </summary>
Id
}
/// <summary>
/// 获取设备值的方式
/// </summary>
@@ -74,7 +101,7 @@ namespace Modbus.Net
}
}
public abstract class BaseMachine<TKey, TUnitKey> : IMachineProperty<TKey> where TKey : IEquatable<TKey>
public abstract class BaseMachine<TKey, TUnitKey> : IMachineData, IMachineProperty<TKey> where TKey : IEquatable<TKey>
where TUnitKey : IEquatable<TUnitKey>
{
private readonly int _maxErrorCount = 3;
@@ -535,6 +562,11 @@ namespace Modbus.Net
return true;
}
/// <summary>
/// 通过Id获取数据字段定义
/// </summary>
/// <param name="addressUnitId">数据字段Id</param>
/// <returns>数据字段</returns>
public AddressUnit<TUnitKey> GetAddressUnitById(TUnitKey addressUnitId)
{
try
@@ -548,6 +580,60 @@ namespace Modbus.Net
}
}
/// <summary>
/// 调用Utility中的方法
/// </summary>
/// <typeparam name="TUtilityMethod">Utility实现的接口名称</typeparam>
/// <typeparam name="TReturnType">返回值的类型</typeparam>
/// <param name="methodName">方法的名称</param>
/// <param name="parameters">方法的参数</param>
/// <returns></returns>
public TReturnType InvokeUtilityMethod<TUtilityMethod, TReturnType>(string methodName,
params object[] parameters) where TUtilityMethod : IUtilityMethod
{
if (BaseUtility is TUtilityMethod)
{
Type t = typeof(TUtilityMethod);
object returnValue = t.GetMethod(methodName,
BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public)
.Invoke(BaseUtility, parameters);
return (TReturnType) returnValue;
}
throw new InvalidCastException($"Utility未实现{typeof(TUtilityMethod).Name}的接口");
}
/// <summary>
/// 调用Machine中的方法
/// </summary>
/// <typeparam name="TMachineMethod">Machine实现的接口名称</typeparam>
/// <typeparam name="TReturnType">返回值的类型</typeparam>
/// <param name="methodName">方法的名称</param>
/// <param name="parameters">方法的参数</param>
/// <returns></returns>
public TReturnType InvokeMachineMethod<TMachineMethod, TReturnType>(string methodName,
params object[] parameters) where TMachineMethod : IMachineMethod
{
if (this is TMachineMethod)
{
Type t = typeof(TMachineMethod);
object returnValue = t.GetMethod(methodName,
BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public)
.Invoke(this, parameters);
return (TReturnType) returnValue;
}
throw new InvalidCastException($"Machine未实现{typeof(TMachineMethod).Name}的接口");
}
/// <summary>
/// 获取Utility
/// </summary>
/// <typeparam name="TUtilityMethod">Utility实现的接口名称</typeparam>
/// <returns></returns>
public TUtilityMethod GetUtility<TUtilityMethod>() where TUtilityMethod : class, IUtilityMethod
{
return BaseUtility as TUtilityMethod;
}
/// <summary>
/// 连接设备
/// </summary>

View File

@@ -17,7 +17,7 @@ namespace Modbus.Net
/// <summary>
/// 基础Api入口
/// </summary>
public abstract class BaseUtility
public abstract class BaseUtility : IUtilityData
{
/// <summary>
/// 协议收发主体
@@ -215,21 +215,6 @@ namespace Modbus.Net
/// <returns>是否设置成功</returns>
public abstract Task<bool> SetDatasAsync(string startAddress, object[] setContents);
/*
/// <summary>
/// 获取PLC时间
/// </summary>
/// <returns>PLC时间</returns>
public abstract DateTime GetTime();
/// <summary>
/// 设置PLC时间
/// </summary>
/// <param name="setTime">设置PLC时间</param>
/// <returns>设置是否成功</returns>
public abstract bool SetTime(DateTime setTime);
*/
/// <summary>
/// 连接设备
/// </summary>

View File

@@ -0,0 +1,47 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Modbus.Net
{
public interface IMachineMethod
{
}
/// <summary>
/// Machine的数据读写接口
/// </summary>
public interface IMachineData : IMachineMethod
{
/// <summary>
/// 读取数据
/// </summary>
/// <returns>从设备读取的数据</returns>
Dictionary<string, ReturnUnit> GetDatas(MachineGetDataType getDataType);
/// <summary>
/// 读取数据
/// </summary>
/// <returns>从设备读取的数据</returns>
Task<Dictionary<string, ReturnUnit>> GetDatasAsync(MachineGetDataType getDataType);
/// <summary>
/// 写入数据
/// </summary>
/// <param name="setDataType">写入类型</param>
/// <param name="values">需要写入的数据字典当写入类型为Address时键为需要写入的地址当写入类型为CommunicationTag时键为需要写入的单元的描述</param>
/// <returns>是否写入成功</returns>
bool SetDatas(MachineSetDataType setDataType, Dictionary<string, double> values);
/// <summary>
/// 写入数据
/// </summary>
/// <param name="setDataType">写入类型</param>
/// <param name="values">需要写入的数据字典当写入类型为Address时键为需要写入的地址当写入类型为CommunicationTag时键为需要写入的单元的描述</param>
/// <returns>是否写入成功</returns>
Task<bool> SetDatasAsync(MachineSetDataType setDataType, Dictionary<string, double> values);
}
}

View File

@@ -0,0 +1,113 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Modbus.Net
{
public interface IUtilityMethod
{
}
/// <summary>
/// Utility的数据读写接口
/// </summary>
public interface IUtilityData : IUtilityMethod
{
/// <summary>
/// 获取数据
/// </summary>
/// <param name="startAddress">开始地址</param>
/// <param name="getByteCount">获取字节数个数</param>
/// <returns>接收到的byte数据</returns>
Task<byte[]> GetDatasAsync(string startAddress, int getByteCount);
/// <summary>
/// 获取数据
/// </summary>
/// <param name="startAddress">开始地址</param>
/// <param name="getTypeAndCount">获取类型和个数</param>
/// <returns>接收到的对应的类型和数据</returns>
object[] GetDatas(string startAddress, KeyValuePair<Type, int> getTypeAndCount);
/// <summary>
/// 获取数据
/// </summary>
/// <param name="startAddress">开始地址</param>
/// <param name="getTypeAndCount">获取类型和个数</param>
/// <returns>接收到的对应的类型和数据</returns>
Task<object[]> GetDatasAsync(string startAddress, KeyValuePair<Type, int> getTypeAndCount);
/// <summary>
/// 获取数据
/// </summary>
/// <typeparam name="T">需要接收的类型</typeparam>
/// <param name="startAddress">开始地址</param>
/// <param name="getByteCount">获取字节数个数</param>
/// <returns>接收到的对应的类型和数据</returns>
T[] GetDatas<T>(string startAddress, int getByteCount);
/// <summary>
/// 获取数据
/// </summary>
/// <typeparam name="T">需要接收的类型</typeparam>
/// <param name="startAddress">开始地址</param>
/// <param name="getByteCount">获取字节数个数</param>
/// <returns>接收到的对应的类型和数据</returns>
Task<T[]> GetDatasAsync<T>(string startAddress, int getByteCount);
/// <summary>
/// 获取数据
/// </summary>
/// <param name="startAddress">开始地址</param>
/// <param name="getTypeAndCountList">获取类型和个数的队列</param>
/// <returns>获取数据的对象数组,请强制转换成相应类型</returns>
object[] GetDatas(string startAddress, IEnumerable<KeyValuePair<Type, int>> getTypeAndCountList);
/// <summary>GetEndian
/// 获取数据
/// </summary>
/// <param name="startAddress">开始地址</param>
/// <param name="getTypeAndCountList">获取类型和个数的队列</param>
Task<object[]> GetDatasAsync(string startAddress, IEnumerable<KeyValuePair<Type, int>> getTypeAndCountList);
/// <summary>
/// 设置数据
/// </summary>
/// <param name="startAddress">开始地址</param>
/// <param name="setContents">设置数据</param>
/// <returns>是否设置成功</returns>
bool SetDatas(string startAddress, object[] setContents);
/// <summary>
/// 设置数据
/// </summary>
/// <param name="startAddress">开始地址</param>
/// <param name="setContents">设置数据</param>
/// <returns>是否设置成功</returns>
Task<bool> SetDatasAsync(string startAddress, object[] setContents);
}
/// <summary>
/// Utility的时间读写接口
/// </summary>
public interface IUtilityTime : IUtilityMethod
{
/// <summary>
/// 获取PLC时间
/// </summary>
/// <returns>PLC时间</returns>
Task<DateTime> GetTimeAsync();
/// <summary>
/// 设置PLC时间
/// </summary>
/// <param name="setTime">设置PLC时间</param>
/// <returns>设置是否成功</returns>
Task<bool> SetTimeAsync(DateTime setTime);
}
}

View File

@@ -11,17 +11,6 @@ using System.Threading.Tasks;
namespace Modbus.Net
{
/// <summary>
/// 设备的读写方式
/// </summary>
public enum MachineDataType
{
Address,
CommunicationTag,
Name,
Id
}
/// <summary>
/// 返回结果的定义类
/// </summary>

View File

@@ -0,0 +1,62 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Modbus.Net.Modbus;
namespace Modbus.Net.Tests
{
[TestClass]
public class MachineUtilityMethodTest
{
[TestMethod]
public void GetUtility()
{
BaseMachine<int, int> baseMachine = new ModbusMachine<int, int>(ModbusType.Tcp, "192.168.3.12", null, true, 2, 0);
var utility = baseMachine.GetUtility<IUtilityTime>();
var methods = utility.GetType().GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly);
Assert.AreEqual(methods.FirstOrDefault(method => method.Name == "GetTimeAsync") != null, true);
Assert.AreEqual(methods.FirstOrDefault(method => method.Name == "SetTimeAsync") != null, true);
}
[TestMethod]
public async Task InvokeUtility()
{
BaseMachine<int, int> baseMachine = new ModbusMachine<int, int>(ModbusType.Tcp, "192.168.3.12", null, true, 2, 0);
var success = baseMachine.InvokeUtilityMethod<IUtilityTime, Task<bool>>("SetTimeAsync", DateTime.Now);
Assert.AreEqual(await success, true);
var time = baseMachine.InvokeUtilityMethod<IUtilityTime, Task<DateTime>>("GetTimeAsync");
Assert.AreEqual(((await time).ToUniversalTime() - DateTime.Now.ToUniversalTime()).Seconds < 10, true);
}
[TestMethod]
public async Task InvokeMachine()
{
BaseMachine<int, int> baseMachine = new ModbusMachine<int, int>(ModbusType.Tcp, "192.168.3.12", new List<AddressUnit<int>>
{
new AddressUnit<int>
{
Id = 0,
Area = "0X",
Address = 1,
SubAddress = 0,
CommunicationTag = "A1",
DataType = typeof(bool)
}
}, true, 2, 0);
var success = baseMachine.InvokeMachineMethod<IMachineData, Task<bool>>("SetDatasAsync",
MachineSetDataType.Address,
new Dictionary<string, double>
{
{
"0X 1.0", 1
}
});
Assert.AreEqual(await success, true);
var datas = baseMachine.InvokeMachineMethod<IMachineData, Task<Dictionary<string, ReturnUnit>>>("GetDatasAsync", MachineGetDataType.Address);
Assert.AreEqual((await datas)["0X 1.0"], 1);
}
}
}

View File

@@ -57,6 +57,7 @@
<Compile Include="SiemensTest.cs" />
<Compile Include="BaseTest.cs" />
<Compile Include="OpcTest.cs" />
<Compile Include="MachineUtilityMethodTest.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\Modbus.Net\Modbus.Net.Modbus\Modbus.Net.Modbus.csproj">