2018-01-05 Update 1 Add duplicate message in controller
This commit is contained in:
@@ -1,4 +1,5 @@
|
|||||||
using System.Configuration;
|
using System.Collections.Generic;
|
||||||
|
using System.Configuration;
|
||||||
|
|
||||||
namespace Modbus.Net.Modbus
|
namespace Modbus.Net.Modbus
|
||||||
{
|
{
|
||||||
@@ -23,7 +24,7 @@ namespace Modbus.Net.Modbus
|
|||||||
/// <param name="port">端口</param>
|
/// <param name="port">端口</param>
|
||||||
public ModbusTcpProtocolLinker(string ip, int port) : base(ip, port)
|
public ModbusTcpProtocolLinker(string ip, int port) : base(ip, port)
|
||||||
{
|
{
|
||||||
((BaseConnector)BaseConnector).AddController(new FifoController(0));
|
((BaseConnector)BaseConnector).AddController(new FifoController(0, true, DuplicateWithCount.GetDuplcateFunc(new List<int>{4,5})));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using System.Configuration;
|
using System.Collections.Generic;
|
||||||
|
using System.Configuration;
|
||||||
|
|
||||||
namespace Modbus.Net.Modbus
|
namespace Modbus.Net.Modbus
|
||||||
{
|
{
|
||||||
@@ -23,7 +24,7 @@ namespace Modbus.Net.Modbus
|
|||||||
/// <param name="port">端口</param>
|
/// <param name="port">端口</param>
|
||||||
public ModbusUdpProtocolLinker(string ip, int port) : base(ip, port)
|
public ModbusUdpProtocolLinker(string ip, int port) : base(ip, port)
|
||||||
{
|
{
|
||||||
((BaseConnector)BaseConnector).AddController(new FifoController(0));
|
((BaseConnector)BaseConnector).AddController(new FifoController(0, true, DuplicateWithCount.GetDuplcateFunc(new List<int> { 4, 5 })));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Configuration;
|
using System.Configuration;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
namespace Modbus.Net.Siemens
|
namespace Modbus.Net.Siemens
|
||||||
{
|
{
|
||||||
@@ -26,7 +27,7 @@ namespace Modbus.Net.Siemens
|
|||||||
public SiemensTcpProtocolLinker(string ip, int port)
|
public SiemensTcpProtocolLinker(string ip, int port)
|
||||||
: base(ip, port)
|
: base(ip, port)
|
||||||
{
|
{
|
||||||
((BaseConnector)BaseConnector).AddController(new MatchDirectlySendController(new ICollection<(int,int)>[] { new List<(int,int)> { (11,11), (12,12) } }));
|
((BaseConnector)BaseConnector).AddController(new MatchDirectlySendController(new ICollection<(int,int)>[] { new List<(int,int)> { (11,11), (12,12) } }, DuplicateWithCount.GetDuplcateFunc(new List<int>{2, 3})));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -489,9 +489,12 @@ namespace Modbus.Net
|
|||||||
$"Com client {ConnectionToken} receive msg: {String.Concat(returnBytes.Select(p => " " + p.ToString("X2")))}");
|
$"Com client {ConnectionToken} receive msg: {String.Concat(returnBytes.Select(p => " " + p.ToString("X2")))}");
|
||||||
|
|
||||||
var isMessageConfirmed = Controller.ConfirmMessage(returnBytes);
|
var isMessageConfirmed = Controller.ConfirmMessage(returnBytes);
|
||||||
if (isMessageConfirmed == false)
|
foreach (var confirmed in isMessageConfirmed)
|
||||||
{
|
{
|
||||||
//主动传输事件
|
if (confirmed == false)
|
||||||
|
{
|
||||||
|
//主动传输事件
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
RefreshReceiveCount();
|
RefreshReceiveCount();
|
||||||
@@ -239,11 +239,14 @@ namespace Modbus.Net
|
|||||||
Log.Verbose(
|
Log.Verbose(
|
||||||
$"Tcp client {ConnectionToken} receive: {String.Concat(receiveBytes.Select(p => " " + p.ToString("X2")))}");
|
$"Tcp client {ConnectionToken} receive: {String.Concat(receiveBytes.Select(p => " " + p.ToString("X2")))}");
|
||||||
var isMessageConfirmed = Controller.ConfirmMessage(receiveBytes);
|
var isMessageConfirmed = Controller.ConfirmMessage(receiveBytes);
|
||||||
if (isMessageConfirmed == false)
|
foreach (var confirmed in isMessageConfirmed)
|
||||||
{
|
{
|
||||||
//主动传输事件
|
if (confirmed == false)
|
||||||
|
{
|
||||||
|
//主动传输事件
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
RefreshReceiveCount();
|
RefreshReceiveCount();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -220,9 +220,12 @@ namespace Modbus.Net
|
|||||||
Log.Verbose(
|
Log.Verbose(
|
||||||
$"Udp client {ConnectionToken} receive: {String.Concat(receiveBytes.Select(p => " " + p.ToString("X2")))}");
|
$"Udp client {ConnectionToken} receive: {String.Concat(receiveBytes.Select(p => " " + p.ToString("X2")))}");
|
||||||
var isMessageConfirmed = Controller.ConfirmMessage(receiveBytes);
|
var isMessageConfirmed = Controller.ConfirmMessage(receiveBytes);
|
||||||
if (isMessageConfirmed == false)
|
foreach (var confirmed in isMessageConfirmed)
|
||||||
{
|
{
|
||||||
//主动传输事件
|
if (confirmed == false)
|
||||||
|
{
|
||||||
|
//主动传输事件
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -21,12 +21,19 @@ namespace Modbus.Net
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
protected Task SendingThread { get; set; }
|
protected Task SendingThread { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// °üÇзÖλÖÃ
|
||||||
|
/// </summary>
|
||||||
|
protected Func<byte[], ICollection<byte[]>> DuplicateFunc { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 构造器
|
/// 构造器
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected BaseController()
|
/// <param name="duplicateFunc">°üÇзֺ¯Êý</param>
|
||||||
|
protected BaseController(Func<byte[], ICollection<byte[]>> duplicateFunc = null)
|
||||||
{
|
{
|
||||||
WaitingMessages = new List<MessageWaitingDef>();
|
WaitingMessages = new List<MessageWaitingDef>();
|
||||||
|
DuplicateFunc = duplicateFunc;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
@@ -97,22 +104,31 @@ namespace Modbus.Net
|
|||||||
protected abstract (string,string)? GetKeyFromMessage(byte[] message);
|
protected abstract (string,string)? GetKeyFromMessage(byte[] message);
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public bool ConfirmMessage(byte[] receiveMessage)
|
public ICollection<bool> ConfirmMessage(byte[] receiveMessage)
|
||||||
{
|
{
|
||||||
var def = GetMessageFromWaitingList(receiveMessage);
|
var ans = new List<bool>();
|
||||||
if (def != null)
|
var duplicatedMessages = DuplicateFunc?.Invoke(receiveMessage);
|
||||||
|
duplicatedMessages = duplicatedMessages ?? new List<byte[]> {receiveMessage};
|
||||||
|
foreach (var message in duplicatedMessages)
|
||||||
{
|
{
|
||||||
def.ReceiveMessage = receiveMessage;
|
var def = GetMessageFromWaitingList(message);
|
||||||
lock (WaitingMessages)
|
if (def != null)
|
||||||
{
|
{
|
||||||
WaitingMessages.Remove(def);
|
def.ReceiveMessage = receiveMessage;
|
||||||
|
lock (WaitingMessages)
|
||||||
|
{
|
||||||
|
WaitingMessages.Remove(def);
|
||||||
|
}
|
||||||
|
def.ReceiveMutex.Set();
|
||||||
|
ans.Add(true);
|
||||||
}
|
}
|
||||||
def.ReceiveMutex.Set();
|
ans.Add(false);
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
return false;
|
return ans;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 从等待队列中匹配信息
|
/// 从等待队列中匹配信息
|
||||||
/// </summary>
|
/// </summary>
|
||||||
59
Modbus.Net/Modbus.Net/Controller/DuplicateWithCount.cs
Normal file
59
Modbus.Net/Modbus.Net/Controller/DuplicateWithCount.cs
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Modbus.Net
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 按照长度断包的函数
|
||||||
|
/// </summary>
|
||||||
|
public static class DuplicateWithCount
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 切分包
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="receiveMessage">收到的报文信息</param>
|
||||||
|
/// <param name="packageCountPositions">收到的断包长度查询位置</param>
|
||||||
|
/// <returns>切分后的报文信息</returns>
|
||||||
|
private static ICollection<byte[]> DuplicateMessages(byte[] receiveMessage, ICollection<int> packageCountPositions)
|
||||||
|
{
|
||||||
|
if (packageCountPositions == null)
|
||||||
|
return new List<byte[]> { receiveMessage };
|
||||||
|
var ans = new List<byte[]>();
|
||||||
|
var pos = 0;
|
||||||
|
while (pos < receiveMessage.Length)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var length = 0;
|
||||||
|
foreach (var countPos in packageCountPositions)
|
||||||
|
{
|
||||||
|
length = length * 256 + receiveMessage[pos + countPos];
|
||||||
|
}
|
||||||
|
if (pos + length > receiveMessage.Length) break;
|
||||||
|
byte[] currentPackage = new byte[length];
|
||||||
|
Array.Copy(receiveMessage, pos, currentPackage, 0, length);
|
||||||
|
ans.Add(currentPackage);
|
||||||
|
pos += length;
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ans;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取按照长度断包的函数
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="packageCountPositions">断包长度的位置信息</param>
|
||||||
|
/// <returns>断包函数</returns>
|
||||||
|
public static Func<byte[], ICollection<byte[]>> GetDuplcateFunc(ICollection<int> packageCountPositions)
|
||||||
|
{
|
||||||
|
return receiveMessage => DuplicateMessages(receiveMessage, packageCountPositions);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using Serilog;
|
using Serilog;
|
||||||
@@ -28,7 +29,9 @@ namespace Modbus.Net
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="acquireTime">间隔时间</param>
|
/// <param name="acquireTime">间隔时间</param>
|
||||||
/// <param name="activateSema">是否开启信号量</param>
|
/// <param name="activateSema">是否开启信号量</param>
|
||||||
public FifoController(int acquireTime, bool activateSema = true)
|
/// <param name="duplicateFunc">包切分函数</param>
|
||||||
|
public FifoController(int acquireTime, bool activateSema = true, Func<byte[], ICollection<byte[]>> duplicateFunc = null)
|
||||||
|
: base(duplicateFunc)
|
||||||
{
|
{
|
||||||
if (activateSema)
|
if (activateSema)
|
||||||
{
|
{
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
using System.Collections.Generic;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
|
||||||
namespace Modbus.Net
|
namespace Modbus.Net
|
||||||
@@ -19,7 +20,9 @@ namespace Modbus.Net
|
|||||||
/// <param name="keyMatches">匹配字典,每个Collection代表一个匹配集合,每一个匹配集合中的数字代表需要匹配的位置,最后计算出来的数字是所有位置数字按照集合排序后叠放在一起</param>
|
/// <param name="keyMatches">匹配字典,每个Collection代表一个匹配集合,每一个匹配集合中的数字代表需要匹配的位置,最后计算出来的数字是所有位置数字按照集合排序后叠放在一起</param>
|
||||||
/// <param name="acquireTime">获取间隔</param>
|
/// <param name="acquireTime">获取间隔</param>
|
||||||
/// <param name="activateSema">是否开启信号量</param>
|
/// <param name="activateSema">是否开启信号量</param>
|
||||||
public MatchController(ICollection<(int,int)>[] keyMatches, int acquireTime, bool activateSema = true) : base(acquireTime, activateSema)
|
/// <param name="duplicateFunc">包切分函数</param>
|
||||||
|
public MatchController(ICollection<(int, int)>[] keyMatches, int acquireTime, bool activateSema = true,
|
||||||
|
Func<byte[], ICollection<byte[]>> duplicateFunc = null) : base(acquireTime, activateSema, duplicateFunc)
|
||||||
{
|
{
|
||||||
KeyMatches = keyMatches;
|
KeyMatches = keyMatches;
|
||||||
}
|
}
|
||||||
@@ -12,8 +12,9 @@ namespace Modbus.Net
|
|||||||
public class MatchDirectlySendController : MatchController
|
public class MatchDirectlySendController : MatchController
|
||||||
{
|
{
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public MatchDirectlySendController(ICollection<(int, int)>[] keyMatches) : base(keyMatches,
|
public MatchDirectlySendController(ICollection<(int, int)>[] keyMatches,
|
||||||
0, false)
|
Func<byte[], ICollection<byte[]>> duplicateFunc = null) : base(keyMatches,
|
||||||
|
0, false, duplicateFunc)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1,3 +1,5 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace Modbus.Net
|
namespace Modbus.Net
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -32,7 +34,7 @@ namespace Modbus.Net
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="receiveMessage">返回的信息</param>
|
/// <param name="receiveMessage">返回的信息</param>
|
||||||
/// <returns>是否正常确认</returns>
|
/// <returns>是否正常确认</returns>
|
||||||
bool ConfirmMessage(byte[] receiveMessage);
|
ICollection<bool> ConfirmMessage(byte[] receiveMessage);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 没有任何返回时强行删除等待队列上的信息
|
/// 没有任何返回时强行删除等待队列上的信息
|
||||||
@@ -1,126 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Diagnostics;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Reflection;
|
|
||||||
|
|
||||||
namespace Modbus.Net
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Extensions of Reflection
|
|
||||||
/// </summary>
|
|
||||||
public static class TypeExtensions
|
|
||||||
{
|
|
||||||
#region Public Methods
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Looks for the method in the type matching the name and arguments.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="type"></param>
|
|
||||||
/// <param name="methodName">
|
|
||||||
/// The name of the method to find.
|
|
||||||
/// </param>
|
|
||||||
/// <param name="args">
|
|
||||||
/// The types of the method's arguments to match.
|
|
||||||
/// </param>
|
|
||||||
/// <param name="isGenericMethod">
|
|
||||||
/// Is method Generic Method.
|
|
||||||
/// </param>
|
|
||||||
/// <returns></returns>
|
|
||||||
/// <exception cref="ArgumentNullException">
|
|
||||||
/// Thrown if:
|
|
||||||
/// - The name of the method is not specified.
|
|
||||||
/// </exception>
|
|
||||||
public static MethodInfo GetRuntimeMethod(this Type type, string methodName, Type[] args, bool isGenericMethod)
|
|
||||||
{
|
|
||||||
if (ReferenceEquals(type, null))
|
|
||||||
throw new NullReferenceException("The type has not been specified.");
|
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(methodName))
|
|
||||||
throw new ArgumentNullException(nameof(methodName), "The name of the method has not been specified.");
|
|
||||||
|
|
||||||
|
|
||||||
var methods =
|
|
||||||
type.GetRuntimeMethods()
|
|
||||||
.Where(methodInfo => string.Equals(methodInfo.Name, methodName, StringComparison.OrdinalIgnoreCase))
|
|
||||||
.ToList();
|
|
||||||
|
|
||||||
if (!methods.Any())
|
|
||||||
return null; // No methods have the specified name.
|
|
||||||
|
|
||||||
if (isGenericMethod)
|
|
||||||
methods = methods.Where(method => method.IsGenericMethod).ToList();
|
|
||||||
else
|
|
||||||
methods = methods.Where(method => !method.IsGenericMethod).ToList();
|
|
||||||
|
|
||||||
var ans = methods.Where(method => IsSignatureMatch(method, args));
|
|
||||||
|
|
||||||
if (ans.Count() <= 1)
|
|
||||||
return ans.Count() == 1 ? ans.Single() : null;
|
|
||||||
|
|
||||||
// Oh noes, don't make me go there.
|
|
||||||
throw new NotImplementedException("Resolving overloaded methods is not implemented as of now.");
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Private Methods
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Finds out if the provided arguments matches the specified method's signature.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="methodInfo"></param>
|
|
||||||
/// <param name="args"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
private static bool IsSignatureMatch(MethodBase methodInfo, Type[] args)
|
|
||||||
{
|
|
||||||
Debug.Assert(!ReferenceEquals(methodInfo, null), "The methodInfo has not been specified.");
|
|
||||||
|
|
||||||
|
|
||||||
// Gets the parameters of the method to analyze.
|
|
||||||
var parameters = methodInfo.GetParameters();
|
|
||||||
|
|
||||||
var currentArgId = 0;
|
|
||||||
|
|
||||||
foreach (var parameterInfo in parameters)
|
|
||||||
{
|
|
||||||
if (!ReferenceEquals(args, null) && currentArgId < args.Length)
|
|
||||||
{
|
|
||||||
// Find out if the types matchs.
|
|
||||||
if (parameterInfo.ParameterType == args[currentArgId])
|
|
||||||
{
|
|
||||||
currentArgId++;
|
|
||||||
continue; // Yeah! Try the next one.
|
|
||||||
}
|
|
||||||
|
|
||||||
// Is this a generic parameter?
|
|
||||||
if (parameterInfo.ParameterType.IsGenericParameter)
|
|
||||||
{
|
|
||||||
// Gets the base type of the generic parameter.
|
|
||||||
var baseType = parameterInfo.ParameterType.GetTypeInfo().BaseType;
|
|
||||||
|
|
||||||
|
|
||||||
// TODO: This is not good v and works with the most simple situation.
|
|
||||||
// Does the base type match?
|
|
||||||
if (args[currentArgId].GetTypeInfo().BaseType == baseType)
|
|
||||||
{
|
|
||||||
currentArgId++;
|
|
||||||
continue; // Yeah! Go on to the next parameter.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Is this parameter optional or does it have a default value?
|
|
||||||
if (parameterInfo.IsOptional || parameterInfo.HasDefaultValue)
|
|
||||||
continue; // Uhum. So let's ignore this parameter for now.
|
|
||||||
|
|
||||||
// No need to go further. It does not match :(
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ye!
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user