2017-05-03 update 1 Base Connector Template (Not Test)

This commit is contained in:
parallelbgls
2017-05-03 17:08:50 +08:00
parent 3a7cfaf17b
commit 5b3854748c
15 changed files with 437 additions and 238 deletions

View File

@@ -45,4 +45,18 @@ namespace Modbus.Net.OPC
public Node RootNodeBase => RootNode; public Node RootNodeBase => RootNode;
} }
public class OpcParamIn
{
public bool IsRead { get; set; }
public string Tag { get; set; }
public char Split { get; set; }
public object SetValue { get; set; }
}
public class OpcParamOut
{
public bool Success { get; set; }
public byte[] Value { get; set; }
}
} }

View File

@@ -8,7 +8,7 @@ using System.Threading.Tasks;
namespace Modbus.Net.OPC namespace Modbus.Net.OPC
{ {
public abstract class OpcConnector : BaseConnector public abstract class OpcConnector : BaseConnector<OpcParamIn, OpcParamOut>
{ {
protected IClientExtend Client; protected IClientExtend Client;
@@ -39,17 +39,17 @@ namespace Modbus.Net.OPC
} }
} }
public override bool SendMsgWithoutReturn(byte[] message) public override bool SendMsgWithoutReturn(OpcParamIn message)
{ {
throw new NotImplementedException(); throw new NotImplementedException();
} }
public override Task<bool> SendMsgWithoutReturnAsync(byte[] message) public override Task<bool> SendMsgWithoutReturnAsync(OpcParamIn message)
{ {
throw new NotImplementedException(); throw new NotImplementedException();
} }
public override byte[] SendMsg(byte[] message) public override OpcParamOut SendMsg(OpcParamIn message)
{ {
return AsyncHelper.RunSync(() => SendMsgAsync(message)); return AsyncHelper.RunSync(() => SendMsgAsync(message));
} }
@@ -88,82 +88,41 @@ namespace Modbus.Net.OPC
return tagSplitList.ToArray(); return tagSplitList.ToArray();
} }
public override async Task<byte[]> SendMsgAsync(byte[] message) public override async Task<OpcParamOut> SendMsgAsync(OpcParamIn message)
{ {
try try
{ {
var pos = 0; if (message.IsRead)
var protocal = BigEndianValueHelper.Instance.GetByte(message, ref pos);
if (protocal == 0)
{ {
var tagBytes = new byte[message.Length - 6]; var split = message.Split;
Array.Copy(message, 1, tagBytes, 0, tagBytes.Length); var tag = message.Tag;
pos += tagBytes.Length; var tagSplit = SplitTag(tag, split);
pos += 4;
var split = Encoding.UTF8.GetString(new[] { message[pos] });
var tag = Encoding.UTF8.GetString(tagBytes);
var tagSplit = SplitTag(tag, split[0]);
var rootDirectory = await Client.ExploreFolderAsync(""); var rootDirectory = await Client.ExploreFolderAsync("");
var answerTag = await SearchTag(tagSplit, split[0], 0, rootDirectory); var answerTag = await SearchTag(tagSplit, split, 0, rootDirectory);
if (answerTag != null) if (answerTag != null)
{ {
var result = await Client.ReadAsync<object>(answerTag); var result = await Client.ReadAsync<object>(answerTag);
return BigEndianValueHelper.Instance.GetBytes(result, result.GetType()); return new OpcParamOut
{
Success = true,
Value = BigEndianValueHelper.Instance.GetBytes(result, result.GetType())
};
} }
return Encoding.ASCII.GetBytes("NoData"); return new OpcParamOut()
{
Success = false,
Value = Encoding.ASCII.GetBytes("NoData")
};
} }
else else
{ {
var index = 0; var tag = message.Tag;
for (var i = 1; i < message.Length - 3; i++) var split = message.Split;
{ var value = message.SetValue;
if (message[i] == 0x00 && message[i + 1] == 0xff && message[i + 2] == 0xff &&
message[i + 3] == 0x00)
{
index = i;
break;
}
}
var index2 = 0;
for (var i = index + 4; i < message.Length - 3; i++)
{
if (message[i] == 0x00 && message[i + 1] == 0xff && message[i + 2] == 0xff &&
message[i + 3] == 0x00)
{
index2 = i;
break;
}
}
var index3 = 0;
for (var i = index2 + 4; i < message.Length - 3; i++)
{
if (message[i] == 0x00 && message[i + 1] == 0xff && message[i + 2] == 0xff &&
message[i + 3] == 0x00)
{
index3 = i;
break;
}
}
var tagBytes = new byte[index - 1];
Array.Copy(message, 1, tagBytes, 0, tagBytes.Length);
var tag = Encoding.UTF8.GetString(tagBytes);
var splitBytes = new byte[index2 - index - 4];
Array.Copy(message, index + 4, splitBytes, 0, splitBytes.Length);
var split = Encoding.UTF8.GetString(splitBytes);
var typeBytes = new byte[index3 - index2 - 4];
Array.Copy(message, index2 + 4, typeBytes, 0, typeBytes.Length);
var type = Type.GetType(Encoding.UTF8.GetString(typeBytes));
var valueBytes = new byte[message.Length - index3 - 4];
Array.Copy(message, index3 + 4, valueBytes, 0, valueBytes.Length);
int mainpos = 0, subpos = 0;
var value = BigEndianValueHelper.Instance.GetValue(valueBytes, ref mainpos, ref subpos, type);
var rootDirectory = await Client.ExploreFolderAsync(""); var rootDirectory = await Client.ExploreFolderAsync("");
var tagSplit = SplitTag(tag, split[0]); var tagSplit = SplitTag(tag, split);
var answerTag = await SearchTag(tagSplit, split[0], 0, rootDirectory); var answerTag = await SearchTag(tagSplit, split, 0, rootDirectory);
if (answerTag != null) if (answerTag != null)
{ {
try try
@@ -173,17 +132,30 @@ namespace Modbus.Net.OPC
catch (Exception e) catch (Exception e)
{ {
AddInfo("opc write exception:" + e.Message); AddInfo("opc write exception:" + e.Message);
return new byte[] { 0 }; return new OpcParamOut()
{
Success = false
};
} }
return new byte[] {1}; return new OpcParamOut()
{
Success = true
};
} }
return new byte[] {0}; return new OpcParamOut()
{
Success = false
};
} }
} }
catch (Exception e) catch (Exception e)
{ {
AddInfo("opc client exception:" + e.Message); AddInfo("opc client exception:" + e.Message);
return Encoding.ASCII.GetBytes("NoData"); return new OpcParamOut()
{
Success = false,
Value = Encoding.ASCII.GetBytes("NoData")
};
} }
} }

View File

@@ -5,7 +5,7 @@ namespace Modbus.Net.OPC
/// <summary> /// <summary>
/// Opc Da协议连接器 /// Opc Da协议连接器
/// </summary> /// </summary>
public class OpcDaProtocalLinker : ProtocalLinker public class OpcDaProtocalLinker : OpcProtocalLinker
{ {
public OpcDaProtocalLinker() : this(ConfigurationManager.OpcDaHost) public OpcDaProtocalLinker() : this(ConfigurationManager.OpcDaHost)
{ {
@@ -15,14 +15,5 @@ namespace Modbus.Net.OPC
{ {
BaseConnector = OpcDaConnector.Instance(host); BaseConnector = OpcDaConnector.Instance(host);
} }
public override bool? CheckRight(byte[] content)
{
if (content != null && content.Length == 6 && Encoding.ASCII.GetString(content) == "NoData")
{
return null;
}
return base.CheckRight(content);
}
} }
} }

View File

@@ -5,7 +5,7 @@ namespace Modbus.Net.OPC
/// <summary> /// <summary>
/// Opc协议 /// Opc协议
/// </summary> /// </summary>
public abstract class OpcProtocal : BaseProtocal public abstract class OpcProtocal : BaseProtocal<OpcParamIn, OpcParamOut, ProtocalUnit<OpcParamIn, OpcParamOut>>
{ {
protected OpcProtocal() : base(0, 0, Endian.BigEndianLsb) protected OpcProtocal() : base(0, 0, Endian.BigEndianLsb)
{ {
@@ -16,14 +16,14 @@ namespace Modbus.Net.OPC
public class ReadRequestOpcInputStruct : IInputStruct public class ReadRequestOpcInputStruct : IInputStruct
{ {
public ReadRequestOpcInputStruct(string tag, string split) public ReadRequestOpcInputStruct(string tag, char split)
{ {
Tag = tag; Tag = tag;
Split = split; Split = split;
} }
public string Tag { get; } public string Tag { get; }
public string Split { get; } public char Split { get; }
} }
public class ReadRequestOpcOutputStruct : IOutputStruct public class ReadRequestOpcOutputStruct : IOutputStruct
@@ -36,17 +36,22 @@ namespace Modbus.Net.OPC
public byte[] GetValue { get; private set; } public byte[] GetValue { get; private set; }
} }
public class ReadRequestOpcProtocal : ProtocalUnit, ISpecialProtocalUnit public class ReadRequestOpcProtocal : ProtocalUnit<OpcParamIn, OpcParamOut>, ISpecialProtocalUnit
{ {
public override byte[] Format(IInputStruct message) public override OpcParamIn Format(IInputStruct message)
{ {
var r_message = (ReadRequestOpcInputStruct) message; var r_message = (ReadRequestOpcInputStruct) message;
return Format((byte) 0x00, Encoding.UTF8.GetBytes(r_message.Tag), 0x00ffff00, Encoding.UTF8.GetBytes(r_message.Split)); return new OpcParamIn()
{
IsRead = true,
Tag = r_message.Tag,
Split = r_message.Split
};
} }
public override IOutputStruct Unformat(byte[] messageBytes, ref int pos) public override IOutputStruct Unformat(OpcParamOut messageBytes, ref int pos)
{ {
return new ReadRequestOpcOutputStruct(messageBytes); return new ReadRequestOpcOutputStruct(messageBytes.Value);
} }
} }
@@ -56,7 +61,7 @@ namespace Modbus.Net.OPC
public class WriteRequestOpcInputStruct : IInputStruct public class WriteRequestOpcInputStruct : IInputStruct
{ {
public WriteRequestOpcInputStruct(string tag, string split, object setValue) public WriteRequestOpcInputStruct(string tag, char split, object setValue)
{ {
Tag = tag; Tag = tag;
Split = split; Split = split;
@@ -64,7 +69,7 @@ namespace Modbus.Net.OPC
} }
public string Tag { get; } public string Tag { get; }
public string Split { get; } public char Split { get; }
public object SetValue { get; } public object SetValue { get; }
} }
@@ -78,20 +83,23 @@ namespace Modbus.Net.OPC
public bool WriteResult { get; private set; } public bool WriteResult { get; private set; }
} }
public class WriteRequestOpcProtocal : ProtocalUnit, ISpecialProtocalUnit public class WriteRequestOpcProtocal : ProtocalUnit<OpcParamIn, OpcParamOut>, ISpecialProtocalUnit
{ {
public override byte[] Format(IInputStruct message) public override OpcParamIn Format(IInputStruct message)
{ {
var r_message = (WriteRequestOpcInputStruct) message; var r_message = (WriteRequestOpcInputStruct) message;
var tag = Encoding.UTF8.GetBytes(r_message.Tag); return new OpcParamIn()
var fullName = Encoding.UTF8.GetBytes(r_message.SetValue.GetType().FullName); {
var split = Encoding.UTF8.GetBytes(r_message.Split); IsRead = false,
return Format((byte) 0x01, tag, 0x00ffff00, split, 0x00ffff00, fullName, 0x00ffff00, r_message.SetValue); Tag = r_message.Tag,
Split = r_message.Split,
SetValue = r_message.SetValue
};
} }
public override IOutputStruct Unformat(byte[] messageBytes, ref int pos) public override IOutputStruct Unformat(OpcParamOut messageBytes, ref int pos)
{ {
var ansByte = BigEndianValueHelper.Instance.GetByte(messageBytes, ref pos); var ansByte = BigEndianValueHelper.Instance.GetByte(messageBytes.Value, ref pos);
var ans = ansByte != 0; var ans = ansByte != 0;
return new WriteRequestOpcOutputStruct(ans); return new WriteRequestOpcOutputStruct(ans);
} }

View File

@@ -0,0 +1,24 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Modbus.Net.OPC
{
/// <summary>
/// Opc协议连接器
/// </summary>
public abstract class OpcProtocalLinker : ProtocalLinker<OpcParamIn, OpcParamOut>
{
public override bool? CheckRight(OpcParamOut content)
{
if (content == null || !content.Success) return false;
if (content.Value.Length == 6 && Encoding.ASCII.GetString(content.Value) == "NoData")
{
return null;
}
return base.CheckRight(content);
}
}
}

View File

@@ -9,7 +9,7 @@ namespace Modbus.Net.OPC
/// <summary> /// <summary>
/// Opc Da协议连接器 /// Opc Da协议连接器
/// </summary> /// </summary>
public class OpcUaProtocalLinker : ProtocalLinker public class OpcUaProtocalLinker : OpcProtocalLinker
{ {
public OpcUaProtocalLinker() : this(ConfigurationManager.OpcUaHost) public OpcUaProtocalLinker() : this(ConfigurationManager.OpcUaHost)
{ {
@@ -19,14 +19,5 @@ namespace Modbus.Net.OPC
{ {
BaseConnector = OpcUaConnector.Instance(host); BaseConnector = OpcUaConnector.Instance(host);
} }
public override bool? CheckRight(byte[] content)
{
if (content != null && content.Length == 6 && Encoding.ASCII.GetString(content) == "NoData")
{
return null;
}
return base.CheckRight(content);
}
} }
} }

View File

@@ -6,7 +6,7 @@ using System.Threading.Tasks;
namespace Modbus.Net.OPC namespace Modbus.Net.OPC
{ {
public abstract class OpcUtility : BaseUtility public abstract class OpcUtility : BaseUtility<OpcParamIn, OpcParamOut>
{ {
protected OpcUtility(string connectionString) : base(0, 0) protected OpcUtility(string connectionString) : base(0, 0)
{ {
@@ -30,7 +30,7 @@ namespace Modbus.Net.OPC
try try
{ {
var split = GetSeperator?.Invoke() ?? '/'; var split = GetSeperator?.Invoke() ?? '/';
var readRequestOpcInputStruct = new ReadRequestOpcInputStruct(startAddress, split.ToString()); var readRequestOpcInputStruct = new ReadRequestOpcInputStruct(startAddress, split);
var readRequestOpcOutputStruct = var readRequestOpcOutputStruct =
await await
Wrapper.SendReceiveAsync<ReadRequestOpcOutputStruct>(Wrapper[typeof(ReadRequestOpcProtocal)], readRequestOpcInputStruct); Wrapper.SendReceiveAsync<ReadRequestOpcOutputStruct>(Wrapper[typeof(ReadRequestOpcProtocal)], readRequestOpcInputStruct);
@@ -47,7 +47,7 @@ namespace Modbus.Net.OPC
try try
{ {
var split = GetSeperator?.Invoke() ?? '/'; var split = GetSeperator?.Invoke() ?? '/';
var writeRequestOpcInputStruct = new WriteRequestOpcInputStruct(startAddress, split.ToString(), setContents[0]); var writeRequestOpcInputStruct = new WriteRequestOpcInputStruct(startAddress, split, setContents[0]);
var writeRequestOpcOutputStruct = var writeRequestOpcOutputStruct =
await await
Wrapper.SendReceiveAsync<WriteRequestOpcOutputStruct>(Wrapper[typeof(WriteRequestOpcProtocal)], writeRequestOpcInputStruct); Wrapper.SendReceiveAsync<WriteRequestOpcOutputStruct>(Wrapper[typeof(WriteRequestOpcProtocal)], writeRequestOpcInputStruct);

View File

@@ -200,7 +200,7 @@ namespace Modbus.Net
/// <summary> /// <summary>
/// 设备的连接器 /// 设备的连接器
/// </summary> /// </summary>
protected BaseUtility BaseUtility { get; set; } public IUtilityProperty BaseUtility { get; protected set; }
/// <summary> /// <summary>
/// 设备的Id /// 设备的Id
@@ -254,7 +254,7 @@ namespace Modbus.Net
//获取数据 //获取数据
var datas = var datas =
await await
BaseUtility.GetDatasAsync( BaseUtility.InvokeUtilityMethod<IUtilityData, Task<byte[]>>("GetDatasAsync",
AddressFormater.FormatAddress(communicateAddress.Area, communicateAddress.Address, AddressFormater.FormatAddress(communicateAddress.Area, communicateAddress.Address,
communicateAddress.SubAddress), communicateAddress.SubAddress),
(int) (int)
@@ -454,7 +454,7 @@ namespace Modbus.Net
var addressStart = AddressFormater.FormatAddress(communicateAddress.Area, var addressStart = AddressFormater.FormatAddress(communicateAddress.Area,
communicateAddress.Address); communicateAddress.Address);
var datasReturn = await BaseUtility.GetDatasAsync( var datasReturn = await BaseUtility.InvokeUtilityMethod<IUtilityData, Task<byte[]>>("GetDatasAsync",
AddressFormater.FormatAddress(communicateAddress.Area, communicateAddress.Address, 0), AddressFormater.FormatAddress(communicateAddress.Area, communicateAddress.Address, 0),
(int) (int)
Math.Ceiling(communicateAddress.GetCount* Math.Ceiling(communicateAddress.GetCount*
@@ -544,7 +544,7 @@ namespace Modbus.Net
} }
//写入数据 //写入数据
await await
BaseUtility.SetDatasAsync(addressStart, BaseUtility.InvokeUtilityMethod<IUtilityData, Task<bool>>("SetDatasAsync",addressStart,
valueHelper.ByteArrayToObjectArray(datas, valueHelper.ByteArrayToObjectArray(datas,
new KeyValuePair<Type, int>(communicateAddress.DataType, communicateAddress.GetCount))); new KeyValuePair<Type, int>(communicateAddress.DataType, communicateAddress.GetCount)));
} }
@@ -580,27 +580,6 @@ 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.GetRuntimeMethod(methodName, parameters.Select(p => p.GetType()).ToArray())
.Invoke(BaseUtility, parameters);
return (TReturnType) returnValue;
}
throw new InvalidCastException($"Utility未实现{typeof(TUtilityMethod).Name}的接口");
}
/// <summary> /// <summary>
/// 调用Machine中的方法 /// 调用Machine中的方法
/// </summary> /// </summary>
@@ -865,6 +844,11 @@ namespace Modbus.Net
/// </summary> /// </summary>
bool KeepConnect { get; set; } bool KeepConnect { get; set; }
/// <summary>
/// 设备的连接器
/// </summary>
IUtilityProperty BaseUtility { get; }
/// <summary> /// <summary>
/// 调用Machine中的方法 /// 调用Machine中的方法
/// </summary> /// </summary>
@@ -877,15 +861,10 @@ namespace Modbus.Net
params object[] parameters) where TMachineMethod : IMachineMethod; params object[] parameters) where TMachineMethod : IMachineMethod;
/// <summary> /// <summary>
/// 调用Utility中的方法 /// 连接设备
/// </summary> /// </summary>
/// <typeparam name="TUtilityMethod">Utility实现的接口名称</typeparam> /// <returns>是否连接成功</returns>
/// <typeparam name="TReturnType">返回值的类型</typeparam> bool Connect();
/// <param name="methodName">方法的名称</param>
/// <param name="parameters">方法的参数</param>
/// <returns></returns>
TReturnType InvokeUtilityMethod<TUtilityMethod, TReturnType>(string methodName,
params object[] parameters) where TUtilityMethod : IUtilityMethod;
/// <summary> /// <summary>
/// 连接设备 /// 连接设备

View File

@@ -8,66 +8,18 @@ namespace Modbus.Net
/// <summary> /// <summary>
/// 基本协议 /// 基本协议
/// </summary> /// </summary>
public abstract class BaseProtocal public abstract class BaseProtocal : BaseProtocal<byte[], byte[], ProtocalUnit>
{ {
/// <summary>
/// 构造器
/// </summary>
protected BaseProtocal(byte slaveAddress, byte masterAddress, Endian endian)
{
Endian = endian;
Protocals = new Dictionary<string, ProtocalUnit>();
SlaveAddress = slaveAddress;
MasterAddress = masterAddress;
}
protected Endian Endian { get; set; }
public byte SlaveAddress { get; set; }
public byte MasterAddress { get; set; }
/// <summary> /// <summary>
/// 协议的连接器 /// 协议的连接器
/// </summary> /// </summary>
public ProtocalLinker ProtocalLinker { get; protected set; } public new ProtocalLinker ProtocalLinker { get; set; }
/// <summary> /// <summary>
/// 协议索引器,这是一个懒加载协议,当字典中不存在协议时自动加载协议,否则调用已经加载的协议 /// 构造器
/// </summary> /// </summary>
/// <param name="type">协议的类的GetType</param> protected BaseProtocal(byte slaveAddress, byte masterAddress, Endian endian) : base(slaveAddress, masterAddress, endian)
/// <returns>协议的实例</returns>
public ProtocalUnit this[Type type]
{ {
get
{
var protocalName = type.FullName;
if (Protocals.ContainsKey(protocalName))
{
return Protocals[protocalName];
}
//自动寻找存在的协议并将其加载
var protocalUnit =
Activator.CreateInstance(type.GetTypeInfo().Assembly.GetType(protocalName)) as ProtocalUnit;
if (protocalUnit == null) throw new InvalidCastException("没有相应的协议内容");
protocalUnit.Endian = Endian;
Register(protocalUnit);
return Protocals[protocalName];
}
}
/// <summary>
/// 协议集合
/// </summary>
protected Dictionary<string, ProtocalUnit> Protocals { get; }
/// <summary>
/// 注册一个协议
/// </summary>
/// <param name="linkProtocal">需要注册的协议</param>
protected void Register(ProtocalUnit linkProtocal)
{
if (linkProtocal == null) return;
Protocals.Add(linkProtocal.GetType().FullName, linkProtocal);
} }
/// <summary> /// <summary>
@@ -85,7 +37,7 @@ namespace Modbus.Net
/// </summary> /// </summary>
/// <param name="content">写入的内容,使用对象数组描述</param> /// <param name="content">写入的内容,使用对象数组描述</param>
/// <returns>从设备获取的字节流</returns> /// <returns>从设备获取的字节流</returns>
public virtual async Task<byte[]> SendReceiveAsync(params object[] content) public override async Task<byte[]> SendReceiveAsync(params object[] content)
{ {
if (ProtocalLinker == null || !ProtocalLinker.IsConnected) if (ProtocalLinker == null || !ProtocalLinker.IsConnected)
{ {
@@ -97,6 +49,72 @@ namespace Modbus.Net
} }
return null; return null;
} }
}
/// <summary>
/// 基本协议
/// </summary>
public abstract class BaseProtocal<TParamIn, TParamOut, TProtocalUnit> where TProtocalUnit : ProtocalUnit<TParamIn, TParamOut>
{
/// <summary>
/// 构造器
/// </summary>
protected BaseProtocal(byte slaveAddress, byte masterAddress, Endian endian)
{
Endian = endian;
Protocals = new Dictionary<string, TProtocalUnit>();
SlaveAddress = slaveAddress;
MasterAddress = masterAddress;
}
protected Endian Endian { get; set; }
public byte SlaveAddress { get; set; }
public byte MasterAddress { get; set; }
/// <summary>
/// 协议的连接器
/// </summary>
public ProtocalLinker<TParamIn, TParamOut> ProtocalLinker { get; protected set; }
/// <summary>
/// 协议索引器,这是一个懒加载协议,当字典中不存在协议时自动加载协议,否则调用已经加载的协议
/// </summary>
/// <param name="type">协议的类的GetType</param>
/// <returns>协议的实例</returns>
public TProtocalUnit this[Type type]
{
get
{
var protocalName = type.FullName;
if (Protocals.ContainsKey(protocalName))
{
return Protocals[protocalName];
}
//自动寻找存在的协议并将其加载
var protocalUnit =
Activator.CreateInstance(type.GetTypeInfo().Assembly.GetType(protocalName)) as TProtocalUnit;
if (protocalUnit == null) throw new InvalidCastException("没有相应的协议内容");
protocalUnit.Endian = Endian;
Register(protocalUnit);
return Protocals[protocalName];
}
}
/// <summary>
/// 协议集合
/// </summary>
protected Dictionary<string, TProtocalUnit> Protocals { get; }
/// <summary>
/// 注册一个协议
/// </summary>
/// <param name="linkProtocal">需要注册的协议</param>
protected void Register(TProtocalUnit linkProtocal)
{
if (linkProtocal == null) return;
Protocals.Add(linkProtocal.GetType().FullName, linkProtocal);
}
/// <summary> /// <summary>
/// 发送协议,通过传入需要使用的协议内容和输入结构 /// 发送协议,通过传入需要使用的协议内容和输入结构
@@ -104,7 +122,7 @@ namespace Modbus.Net
/// <param name="unit">协议的实例</param> /// <param name="unit">协议的实例</param>
/// <param name="content">输入信息的结构化描述</param> /// <param name="content">输入信息的结构化描述</param>
/// <returns>输出信息的结构化描述</returns> /// <returns>输出信息的结构化描述</returns>
public virtual IOutputStruct SendReceive(ProtocalUnit unit, IInputStruct content) public virtual IOutputStruct SendReceive(TProtocalUnit unit, IInputStruct content)
{ {
return AsyncHelper.RunSync(() => SendReceiveAsync(unit, content)); return AsyncHelper.RunSync(() => SendReceiveAsync(unit, content));
} }
@@ -116,7 +134,7 @@ namespace Modbus.Net
/// <param name="content">输入信息的结构化描述</param> /// <param name="content">输入信息的结构化描述</param>
/// <returns>输出信息的结构化描述</returns> /// <returns>输出信息的结构化描述</returns>
/// <typeparam name="T">IOutputStruct的具体类型</typeparam> /// <typeparam name="T">IOutputStruct的具体类型</typeparam>
public virtual T SendReceive<T>(ProtocalUnit unit, IInputStruct content) where T : class, IOutputStruct public virtual T SendReceive<T>(TProtocalUnit unit, IInputStruct content) where T : class, IOutputStruct
{ {
return AsyncHelper.RunSync(() => SendReceiveAsync<T>(unit, content)); return AsyncHelper.RunSync(() => SendReceiveAsync<T>(unit, content));
} }
@@ -127,7 +145,7 @@ namespace Modbus.Net
/// <param name="unit">协议的实例</param> /// <param name="unit">协议的实例</param>
/// <param name="content">输入信息的结构化描述</param> /// <param name="content">输入信息的结构化描述</param>
/// <returns>输出信息的结构化描述</returns> /// <returns>输出信息的结构化描述</returns>
public virtual async Task<IOutputStruct> SendReceiveAsync(ProtocalUnit unit, IInputStruct content) public virtual async Task<IOutputStruct> SendReceiveAsync(TProtocalUnit unit, IInputStruct content)
{ {
return await SendReceiveAsync<IOutputStruct>(unit, content); return await SendReceiveAsync<IOutputStruct>(unit, content);
} }
@@ -139,13 +157,13 @@ namespace Modbus.Net
/// <param name="content">输入信息的结构化描述</param> /// <param name="content">输入信息的结构化描述</param>
/// <returns>输出信息的结构化描述</returns> /// <returns>输出信息的结构化描述</returns>
/// <typeparam name="T">IOutputStruct的具体类型</typeparam> /// <typeparam name="T">IOutputStruct的具体类型</typeparam>
public virtual async Task<T> SendReceiveAsync<T>(ProtocalUnit unit, IInputStruct content) where T : class, IOutputStruct public virtual async Task<T> SendReceiveAsync<T>(TProtocalUnit unit, IInputStruct content) where T : class, IOutputStruct
{ {
var t = 0; var t = 0;
var formatContent = unit.Format(content); var formatContent = unit.Format(content);
if (formatContent != null) if (formatContent != null)
{ {
byte[] receiveContent; TParamOut receiveContent;
//如果为特别处理协议的话,跳过协议扩展收缩 //如果为特别处理协议的话,跳过协议扩展收缩
if (unit is ISpecialProtocalUnit) if (unit is ISpecialProtocalUnit)
{ {
@@ -163,6 +181,11 @@ namespace Modbus.Net
return null; return null;
} }
public virtual async Task<byte[]> SendReceiveAsync(params object[] content)
{
throw new NotImplementedException();
}
/// <summary> /// <summary>
/// 协议连接开始 /// 协议连接开始
/// </summary> /// </summary>

View File

@@ -1,28 +1,59 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Reflection;
using System.Threading.Tasks; using System.Threading.Tasks;
/// <summary>
/// 端格式
/// </summary>
public enum Endian public enum Endian
{ {
/// <summary>
/// 小端
/// </summary>
LittleEndianLsb, LittleEndianLsb,
/// <summary>
/// 大端-小端位
/// </summary>
BigEndianLsb, BigEndianLsb,
/// <summary>
/// 大端-大端位
/// </summary>
BigEndianMsb BigEndianMsb
} }
namespace Modbus.Net namespace Modbus.Net
{ {
/// <summary>
/// 基础Api入口
/// </summary>
public abstract class BaseUtility : BaseUtility<byte[], byte[]>
{
/// <summary>
/// 构造器
/// </summary>
protected BaseUtility(byte slaveAddress, byte masterAddress) : base(slaveAddress, masterAddress)
{
}
/// <summary>
/// 协议收发主体
/// </summary>
protected new BaseProtocal Wrapper;
}
/// <summary> /// <summary>
/// 基础Api入口 /// 基础Api入口
/// </summary> /// </summary>
public abstract class BaseUtility : IUtilityData public abstract class BaseUtility<TParamIn, TParamOut> : IUtilityProperty, IUtilityData
{ {
/// <summary> /// <summary>
/// 协议收发主体 /// 协议收发主体
/// </summary> /// </summary>
protected BaseProtocal Wrapper; protected BaseProtocal<TParamIn, TParamOut, ProtocalUnit<TParamIn, TParamOut>> Wrapper;
/// <summary> /// <summary>
/// 构造器 /// 构造器
@@ -34,9 +65,18 @@ namespace Modbus.Net
AddressTranslator = new AddressTranslatorBase(); AddressTranslator = new AddressTranslatorBase();
} }
/// <summary>
/// 连接字符串
/// </summary>
protected string ConnectionString { get; set; } protected string ConnectionString { get; set; }
/// <summary>
/// 从站号
/// </summary>
public byte SlaveAddress { get; set; } public byte SlaveAddress { get; set; }
/// <summary>
/// 主站号
/// </summary>
public byte MasterAddress { get; set; } public byte MasterAddress { get; set; }
/// <summary> /// <summary>
@@ -241,5 +281,80 @@ namespace Modbus.Net
{ {
return Wrapper.Disconnect(); return Wrapper.Disconnect();
} }
/// <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 (this is TUtilityMethod)
{
Type t = typeof(TUtilityMethod);
object returnValue = t.GetRuntimeMethod(methodName, parameters.Select(p => p.GetType()).ToArray())
.Invoke(this, parameters);
return (TReturnType)returnValue;
}
throw new InvalidCastException($"Utility未实现{typeof(TUtilityMethod).Name}的接口");
}
}
/// <summary>
/// Api入口的抽象
/// </summary>
public interface IUtilityProperty
{
/// <summary>
/// 协议是否遵循小端格式
/// </summary>
Endian Endian { get; }
/// <summary>
/// 设备是否已经连接
/// </summary>
bool IsConnected { get; }
/// <summary>
/// 标识设备的连接关键字
/// </summary>
string ConnectionToken { get; }
/// <summary>
/// 地址翻译器
/// </summary>
AddressTranslator AddressTranslator { get; set; }
/// <summary>
/// 连接设备
/// </summary>
/// <returns>设备是否连接成功</returns>
bool Connect();
/// <summary>
/// 连接设备
/// </summary>
/// <returns>设备是否连接成功</returns>
Task<bool> ConnectAsync();
/// <summary>
/// 断开设备
/// </summary>
/// <returns>设备是否断开成功</returns>
bool Disconnect();
/// <summary>
/// 调用Utility中的方法
/// </summary>
/// <typeparam name="TUtilityMethod">Utility实现的接口名称</typeparam>
/// <typeparam name="TReturnType">返回值的类型</typeparam>
/// <param name="methodName">方法的名称</param>
/// <param name="parameters">方法的参数</param>
/// <returns></returns>
TReturnType InvokeUtilityMethod<TUtilityMethod, TReturnType>(string methodName,
params object[] parameters) where TUtilityMethod : IUtilityMethod;
} }
} }

View File

@@ -3,14 +3,22 @@
/// <summary> /// <summary>
/// 协议转换的接口 /// 协议转换的接口
/// </summary> /// </summary>
public interface IProtocalFormatting public interface IProtocalFormatting : IProtocalFormatting<byte[], byte[]>
{
}
/// <summary>
/// 协议转换的接口
/// </summary>
public interface IProtocalFormatting<out TParamIn, in TParamOut>
{ {
/// <summary> /// <summary>
/// 从输入结构格式化 /// 从输入结构格式化
/// </summary> /// </summary>
/// <param name="message">结构化的输入数据</param> /// <param name="message">结构化的输入数据</param>
/// <returns>格式化后的字节流</returns> /// <returns>格式化后的字节流</returns>
byte[] Format(IInputStruct message); TParamIn Format(IInputStruct message);
/// <summary> /// <summary>
/// 从对象的参数数组格式化 /// 从对象的参数数组格式化
@@ -25,6 +33,15 @@
/// <param name="messageBytes">返回数据的字节流</param> /// <param name="messageBytes">返回数据的字节流</param>
/// <param name="pos">转换标记位</param> /// <param name="pos">转换标记位</param>
/// <returns>结构化的输出数据</returns> /// <returns>结构化的输出数据</returns>
IOutputStruct Unformat(byte[] messageBytes, ref int pos); IOutputStruct Unformat(TParamOut messageBytes, ref int pos);
/// <summary>
/// 把仪器返回的内容填充到输出结构中
/// </summary>
/// <param name="messageBytes">返回数据的字节流</param>
/// <param name="pos">转换标记位</param>
/// <typeparam name="T">IOutputStruct的具体类型</typeparam>
/// <returns>结构化的输出数据</returns>
T Unformat<T>(TParamOut messageBytes, ref int pos) where T : class, IOutputStruct;
} }
} }

View File

@@ -7,9 +7,72 @@ namespace Modbus.Net
/// <summary> /// <summary>
/// 基本的协议连接器 /// 基本的协议连接器
/// </summary> /// </summary>
public abstract class ProtocalLinker public abstract class ProtocalLinker : ProtocalLinker<byte[], byte[]>
{ {
protected BaseConnector BaseConnector; protected new BaseConnector BaseConnector;
/// <summary>
/// 发送并接收数据
/// </summary>
/// <param name="content">发送协议的内容</param>
/// <returns>接收协议的内容</returns>
public override async Task<byte[]> SendReceiveAsync(byte[] content)
{
var extBytes = BytesExtend(content);
var receiveBytes = await SendReceiveWithoutExtAndDecAsync(extBytes);
return receiveBytes == null ? null : receiveBytes.Length == 0 ? receiveBytes : BytesDecact(receiveBytes);
}
/// <summary>
/// 发送并接收数据,不进行协议扩展和收缩,用于特殊协议
/// </summary>
/// <param name="content">发送协议的内容</param>
/// <returns>接收协议的内容</returns>
public override async Task<byte[]> SendReceiveWithoutExtAndDecAsync(byte[] content)
{
//发送数据
var receiveBytes = await BaseConnector.SendMsgAsync(content);
//容错处理
var checkRight = CheckRight(receiveBytes);
return checkRight == null ? new byte[0] : (!checkRight.Value ? null : receiveBytes);
//返回字符
}
/// <summary>
/// 协议内容扩展,发送时根据需要扩展
/// </summary>
/// <param name="content">扩展前的基本协议内容</param>
/// <returns>扩展后的协议内容</returns>
public override byte[] BytesExtend(byte[] content)
{
//自动查找相应的协议放缩类,命令规则为——当前的实际类名(注意是继承后的)+"BytesExtend"。
var bytesExtend =
Activator.CreateInstance(GetType().GetTypeInfo().Assembly.GetType(GetType().FullName + "BytesExtend")) as
IProtocalLinkerBytesExtend;
return bytesExtend?.BytesExtend(content);
}
/// <summary>
/// 协议内容缩减,接收时根据需要缩减
/// </summary>
/// <param name="content">缩减前的完整协议内容</param>
/// <returns>缩减后的协议内容</returns>
public override byte[] BytesDecact(byte[] content)
{
//自动查找相应的协议放缩类,命令规则为——当前的实际类名(注意是继承后的)+"BytesExtend"。
var bytesExtend =
Activator.CreateInstance(GetType().GetTypeInfo().Assembly.GetType(GetType().FullName + "BytesExtend")) as
IProtocalLinkerBytesExtend;
return bytesExtend?.BytesDecact(content);
}
}
/// <summary>
/// 基本的协议连接器
/// </summary>
public abstract class ProtocalLinker<TParamIn, TParamOut>
{
protected BaseConnector<TParamIn, TParamOut> BaseConnector;
public string ConnectionToken => BaseConnector.ConnectionToken; public string ConnectionToken => BaseConnector.ConnectionToken;
@@ -50,7 +113,7 @@ namespace Modbus.Net
/// </summary> /// </summary>
/// <param name="content">发送协议的内容</param> /// <param name="content">发送协议的内容</param>
/// <returns>接收协议的内容</returns> /// <returns>接收协议的内容</returns>
public virtual byte[] SendReceive(byte[] content) public virtual TParamOut SendReceive(TParamIn content)
{ {
return AsyncHelper.RunSync(() => SendReceiveAsync(content)); return AsyncHelper.RunSync(() => SendReceiveAsync(content));
} }
@@ -60,11 +123,12 @@ namespace Modbus.Net
/// </summary> /// </summary>
/// <param name="content">发送协议的内容</param> /// <param name="content">发送协议的内容</param>
/// <returns>接收协议的内容</returns> /// <returns>接收协议的内容</returns>
public virtual async Task<byte[]> SendReceiveAsync(byte[] content) public virtual async Task<TParamOut> SendReceiveAsync(TParamIn content)
{ {
var extBytes = BytesExtend(content); var extBytes = BytesExtend(content);
var receiveBytes = await SendReceiveWithoutExtAndDecAsync(extBytes); var receiveBytes = await SendReceiveWithoutExtAndDecAsync(extBytes);
return receiveBytes == null ? null : receiveBytes.Length == 0 ? receiveBytes : BytesDecact(receiveBytes); if (receiveBytes != null) return receiveBytes;
throw new NullReferenceException();
} }
/// <summary> /// <summary>
@@ -72,7 +136,7 @@ namespace Modbus.Net
/// </summary> /// </summary>
/// <param name="content">发送协议的内容</param> /// <param name="content">发送协议的内容</param>
/// <returns>接收协议的内容</returns> /// <returns>接收协议的内容</returns>
public virtual byte[] SendReceiveWithoutExtAndDec(byte[] content) public virtual TParamOut SendReceiveWithoutExtAndDec(TParamIn content)
{ {
return AsyncHelper.RunSync(() => SendReceiveWithoutExtAndDecAsync(content)); return AsyncHelper.RunSync(() => SendReceiveWithoutExtAndDecAsync(content));
} }
@@ -82,14 +146,15 @@ namespace Modbus.Net
/// </summary> /// </summary>
/// <param name="content">发送协议的内容</param> /// <param name="content">发送协议的内容</param>
/// <returns>接收协议的内容</returns> /// <returns>接收协议的内容</returns>
public virtual async Task<byte[]> SendReceiveWithoutExtAndDecAsync(byte[] content) public virtual async Task<TParamOut> SendReceiveWithoutExtAndDecAsync(TParamIn content)
{ {
//发送数据 //发送数据
var receiveBytes = await BaseConnector.SendMsgAsync(content); var receiveBytes = await BaseConnector.SendMsgAsync(content);
//容错处理 //容错处理
var checkRight = CheckRight(receiveBytes); var checkRight = CheckRight(receiveBytes);
return checkRight == null ? new byte[0] : (!checkRight.Value ? null : receiveBytes);
//返回字符 //返回字符
if (checkRight == true) return receiveBytes;
throw new NullReferenceException();
} }
/// <summary> /// <summary>
@@ -97,7 +162,7 @@ namespace Modbus.Net
/// </summary> /// </summary>
/// <param name="content">接收协议的内容</param> /// <param name="content">接收协议的内容</param>
/// <returns>协议是否是正确的</returns> /// <returns>协议是否是正确的</returns>
public virtual bool? CheckRight(byte[] content) public virtual bool? CheckRight(TParamOut content)
{ {
if (content != null) return true; if (content != null) return true;
Disconnect(); Disconnect();
@@ -109,13 +174,9 @@ namespace Modbus.Net
/// </summary> /// </summary>
/// <param name="content">扩展前的基本协议内容</param> /// <param name="content">扩展前的基本协议内容</param>
/// <returns>扩展后的协议内容</returns> /// <returns>扩展后的协议内容</returns>
public byte[] BytesExtend(byte[] content) public virtual TParamIn BytesExtend(TParamIn content)
{ {
//自动查找相应的协议放缩类,命令规则为——当前的实际类名(注意是继承后的)+"BytesExtend"。 throw new NotImplementedException();
var bytesExtend =
Activator.CreateInstance(GetType().GetTypeInfo().Assembly.GetType(GetType().FullName + "BytesExtend")) as
IProtocalLinkerBytesExtend;
return bytesExtend?.BytesExtend(content);
} }
/// <summary> /// <summary>
@@ -123,13 +184,9 @@ namespace Modbus.Net
/// </summary> /// </summary>
/// <param name="content">缩减前的完整协议内容</param> /// <param name="content">缩减前的完整协议内容</param>
/// <returns>缩减后的协议内容</returns> /// <returns>缩减后的协议内容</returns>
public byte[] BytesDecact(byte[] content) public virtual TParamOut BytesDecact(TParamOut content)
{ {
//自动查找相应的协议放缩类,命令规则为——当前的实际类名(注意是继承后的)+"BytesExtend"。 throw new NotImplementedException();
var bytesExtend =
Activator.CreateInstance(GetType().GetTypeInfo().Assembly.GetType(GetType().FullName + "BytesExtend")) as
IProtocalLinkerBytesExtend;
return bytesExtend?.BytesDecact(content);
} }
} }
} }

View File

@@ -5,7 +5,15 @@ namespace Modbus.Net
/// <summary> /// <summary>
/// 协议单元 /// 协议单元
/// </summary> /// </summary>
public abstract class ProtocalUnit : IProtocalFormatting public abstract class ProtocalUnit : ProtocalUnit<byte[], byte[]>
{
}
/// <summary>
/// 协议单元
/// </summary>
public abstract class ProtocalUnit<TParamIn, TParamOut> : IProtocalFormatting<TParamIn, TParamOut>
{ {
/// <summary> /// <summary>
/// 是否为小端格式 /// 是否为小端格式
@@ -17,7 +25,7 @@ namespace Modbus.Net
/// </summary>s /// </summary>s
/// <param name="message">结构化的输入数据</param> /// <param name="message">结构化的输入数据</param>
/// <returns>格式化后的字节流</returns> /// <returns>格式化后的字节流</returns>
public abstract byte[] Format(IInputStruct message); public abstract TParamIn Format(IInputStruct message);
/// <summary> /// <summary>
/// 从对象的参数数组格式化 /// 从对象的参数数组格式化
@@ -35,7 +43,7 @@ namespace Modbus.Net
/// <param name="messageBytes">返回数据的字节流</param> /// <param name="messageBytes">返回数据的字节流</param>
/// <param name="pos">转换标记位</param> /// <param name="pos">转换标记位</param>
/// <returns>结构化的输出数据</returns> /// <returns>结构化的输出数据</returns>
public abstract IOutputStruct Unformat(byte[] messageBytes, ref int pos); public abstract IOutputStruct Unformat(TParamOut messageBytes, ref int pos);
/// <summary> /// <summary>
/// 把仪器返回的内容填充到输出结构中 /// 把仪器返回的内容填充到输出结构中
@@ -44,7 +52,7 @@ namespace Modbus.Net
/// <param name="pos">转换标记位</param> /// <param name="pos">转换标记位</param>
/// <typeparam name="T">IOutputStruct的具体类型</typeparam> /// <typeparam name="T">IOutputStruct的具体类型</typeparam>
/// <returns>结构化的输出数据</returns> /// <returns>结构化的输出数据</returns>
public T Unformat<T>(byte[] messageBytes, ref int pos) where T : class, IOutputStruct public T Unformat<T>(TParamOut messageBytes, ref int pos) where T : class, IOutputStruct
{ {
return Unformat(messageBytes, ref pos) as T; return Unformat(messageBytes, ref pos) as T;
} }

View File

@@ -58,8 +58,8 @@ namespace TripleAdd.Controllers
new AddressUnit() {Id = "3", Area = "4X", Address = 3, CommunicationTag = "Add3", DataType = typeof(ushort), Zoom = 1, DecimalPos = 0}, new AddressUnit() {Id = "3", Area = "4X", Address = 3, CommunicationTag = "Add3", DataType = typeof(ushort), Zoom = 1, DecimalPos = 0},
new AddressUnit() {Id = "4", Area = "4X", Address = 4, CommunicationTag = "Ans", DataType = typeof(ushort), Zoom = 1, DecimalPos = 0}, new AddressUnit() {Id = "4", Area = "4X", Address = 4, CommunicationTag = "Ans", DataType = typeof(ushort), Zoom = 1, DecimalPos = 0},
}, 2, 0); }, 2, 0);
machine.AddressCombiner = new AddressCombinerContinus(machine.AddressTranslator); machine.AddressCombiner = new AddressCombinerContinus(machine.AddressTranslator, 100000);
machine.AddressCombinerSet = new AddressCombinerContinus(machine.AddressTranslator); machine.AddressCombinerSet = new AddressCombinerContinus(machine.AddressTranslator, 100000);
} }
var resultFormat = (await machine.GetDatasAsync(MachineGetDataType.CommunicationTag)).MapGetValuesToSetValues(); var resultFormat = (await machine.GetDatasAsync(MachineGetDataType.CommunicationTag)).MapGetValuesToSetValues();
return SetValue(new ushort[4] { (ushort)resultFormat["Add1"], (ushort)resultFormat["Add2"], (ushort)resultFormat["Add3"], (ushort)resultFormat["Ans"] }); return SetValue(new ushort[4] { (ushort)resultFormat["Add1"], (ushort)resultFormat["Add2"], (ushort)resultFormat["Add3"], (ushort)resultFormat["Ans"] });

View File

@@ -25,9 +25,9 @@ namespace Modbus.Net.Tests
public async Task InvokeUtility() public async Task InvokeUtility()
{ {
BaseMachine<int, int> baseMachine = new ModbusMachine<int, int>(ModbusType.Tcp, "192.168.3.12", null, true, 2, 0); BaseMachine<int, int> baseMachine = new ModbusMachine<int, int>(ModbusType.Tcp, "192.168.3.12", null, true, 2, 0);
var success = await baseMachine.InvokeUtilityMethod<IUtilityTime, Task<bool>>("SetTimeAsync", DateTime.Now); var success = await baseMachine.BaseUtility.InvokeUtilityMethod<IUtilityTime, Task<bool>>("SetTimeAsync", DateTime.Now);
Assert.AreEqual(success, true); Assert.AreEqual(success, true);
var time = await baseMachine.InvokeUtilityMethod<IUtilityTime, Task<DateTime>>("GetTimeAsync"); var time = await baseMachine.BaseUtility.InvokeUtilityMethod<IUtilityTime, Task<DateTime>>("GetTimeAsync");
Assert.AreEqual((time.ToUniversalTime() - DateTime.Now.ToUniversalTime()).Seconds < 10, true); Assert.AreEqual((time.ToUniversalTime() - DateTime.Now.ToUniversalTime()).Seconds < 10, true);
} }