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
|
||||
{
|
||||
@@ -23,7 +24,7 @@ namespace Modbus.Net.Modbus
|
||||
/// <param name="port">端口</param>
|
||||
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>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.Configuration;
|
||||
using System.Collections.Generic;
|
||||
using System.Configuration;
|
||||
|
||||
namespace Modbus.Net.Modbus
|
||||
{
|
||||
@@ -23,7 +24,7 @@ namespace Modbus.Net.Modbus
|
||||
/// <param name="port">端口</param>
|
||||
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>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Configuration;
|
||||
using System.Linq;
|
||||
|
||||
namespace Modbus.Net.Siemens
|
||||
{
|
||||
@@ -26,7 +27,7 @@ namespace Modbus.Net.Siemens
|
||||
public SiemensTcpProtocolLinker(string ip, int 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>
|
||||
|
||||
@@ -489,9 +489,12 @@ namespace Modbus.Net
|
||||
$"Com client {ConnectionToken} receive msg: {String.Concat(returnBytes.Select(p => " " + p.ToString("X2")))}");
|
||||
|
||||
var isMessageConfirmed = Controller.ConfirmMessage(returnBytes);
|
||||
if (isMessageConfirmed == false)
|
||||
foreach (var confirmed in isMessageConfirmed)
|
||||
{
|
||||
//主动传输事件
|
||||
if (confirmed == false)
|
||||
{
|
||||
//主动传输事件
|
||||
}
|
||||
}
|
||||
|
||||
RefreshReceiveCount();
|
||||
@@ -239,11 +239,14 @@ namespace Modbus.Net
|
||||
Log.Verbose(
|
||||
$"Tcp client {ConnectionToken} receive: {String.Concat(receiveBytes.Select(p => " " + p.ToString("X2")))}");
|
||||
var isMessageConfirmed = Controller.ConfirmMessage(receiveBytes);
|
||||
if (isMessageConfirmed == false)
|
||||
foreach (var confirmed in isMessageConfirmed)
|
||||
{
|
||||
//主动传输事件
|
||||
if (confirmed == false)
|
||||
{
|
||||
//主动传输事件
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
RefreshReceiveCount();
|
||||
}
|
||||
}
|
||||
@@ -220,9 +220,12 @@ namespace Modbus.Net
|
||||
Log.Verbose(
|
||||
$"Udp client {ConnectionToken} receive: {String.Concat(receiveBytes.Select(p => " " + p.ToString("X2")))}");
|
||||
var isMessageConfirmed = Controller.ConfirmMessage(receiveBytes);
|
||||
if (isMessageConfirmed == false)
|
||||
foreach (var confirmed in isMessageConfirmed)
|
||||
{
|
||||
//主动传输事件
|
||||
if (confirmed == false)
|
||||
{
|
||||
//主动传输事件
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,12 +21,19 @@ namespace Modbus.Net
|
||||
/// </summary>
|
||||
protected Task SendingThread { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// °üÇзÖλÖÃ
|
||||
/// </summary>
|
||||
protected Func<byte[], ICollection<byte[]>> DuplicateFunc { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 构造器
|
||||
/// </summary>
|
||||
protected BaseController()
|
||||
/// <param name="duplicateFunc">°üÇзֺ¯Êý</param>
|
||||
protected BaseController(Func<byte[], ICollection<byte[]>> duplicateFunc = null)
|
||||
{
|
||||
WaitingMessages = new List<MessageWaitingDef>();
|
||||
DuplicateFunc = duplicateFunc;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -97,22 +104,31 @@ namespace Modbus.Net
|
||||
protected abstract (string,string)? GetKeyFromMessage(byte[] message);
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool ConfirmMessage(byte[] receiveMessage)
|
||||
public ICollection<bool> ConfirmMessage(byte[] receiveMessage)
|
||||
{
|
||||
var def = GetMessageFromWaitingList(receiveMessage);
|
||||
if (def != null)
|
||||
var ans = new List<bool>();
|
||||
var duplicatedMessages = DuplicateFunc?.Invoke(receiveMessage);
|
||||
duplicatedMessages = duplicatedMessages ?? new List<byte[]> {receiveMessage};
|
||||
foreach (var message in duplicatedMessages)
|
||||
{
|
||||
def.ReceiveMessage = receiveMessage;
|
||||
lock (WaitingMessages)
|
||||
var def = GetMessageFromWaitingList(message);
|
||||
if (def != null)
|
||||
{
|
||||
WaitingMessages.Remove(def);
|
||||
def.ReceiveMessage = receiveMessage;
|
||||
lock (WaitingMessages)
|
||||
{
|
||||
WaitingMessages.Remove(def);
|
||||
}
|
||||
def.ReceiveMutex.Set();
|
||||
ans.Add(true);
|
||||
}
|
||||
def.ReceiveMutex.Set();
|
||||
return true;
|
||||
ans.Add(false);
|
||||
}
|
||||
return false;
|
||||
return ans;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <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.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using Serilog;
|
||||
@@ -28,7 +29,9 @@ namespace Modbus.Net
|
||||
/// </summary>
|
||||
/// <param name="acquireTime">间隔时间</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)
|
||||
{
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Modbus.Net
|
||||
@@ -19,7 +20,9 @@ namespace Modbus.Net
|
||||
/// <param name="keyMatches">匹配字典,每个Collection代表一个匹配集合,每一个匹配集合中的数字代表需要匹配的位置,最后计算出来的数字是所有位置数字按照集合排序后叠放在一起</param>
|
||||
/// <param name="acquireTime">获取间隔</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;
|
||||
}
|
||||
@@ -12,8 +12,9 @@ namespace Modbus.Net
|
||||
public class MatchDirectlySendController : MatchController
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public MatchDirectlySendController(ICollection<(int, int)>[] keyMatches) : base(keyMatches,
|
||||
0, false)
|
||||
public MatchDirectlySendController(ICollection<(int, int)>[] keyMatches,
|
||||
Func<byte[], ICollection<byte[]>> duplicateFunc = null) : base(keyMatches,
|
||||
0, false, duplicateFunc)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Modbus.Net
|
||||
{
|
||||
/// <summary>
|
||||
@@ -32,7 +34,7 @@ namespace Modbus.Net
|
||||
/// </summary>
|
||||
/// <param name="receiveMessage">返回的信息</param>
|
||||
/// <returns>是否正常确认</returns>
|
||||
bool ConfirmMessage(byte[] receiveMessage);
|
||||
ICollection<bool> ConfirmMessage(byte[] receiveMessage);
|
||||
|
||||
/// <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