2018-01-05 Update 1 Add duplicate message in controller

This commit is contained in:
parallelbgls
2018-01-05 11:51:17 +08:00
parent bc92dc631c
commit e8b8c3829e
41 changed files with 124 additions and 154 deletions

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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();

View File

@@ -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();
}
}

View File

@@ -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)
{
//主动传输事件
}
}
}

View File

@@ -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>

View 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);
}
}
}

View File

@@ -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)
{

View File

@@ -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;
}

View File

@@ -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)
{
}

View File

@@ -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>
/// 没有任何返回时强行删除等待队列上的信息

View File

@@ -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
}
}