Fix a critial bug in serial port receive

This commit is contained in:
luosheng
2023-03-21 22:02:51 +08:00
parent 94fdb61f38
commit d8b84f4b5c
17 changed files with 103 additions and 92 deletions

View File

@@ -24,7 +24,7 @@ namespace Modbus.Net.Modbus
public ModbusAsciiInTcpProtocolLinker(string ip, int port)
: base(ip, port)
{
((BaseConnector)BaseConnector).AddController(new FifoController(int.Parse(ConfigurationReader.GetValue("TCP:" + ip + ":" + port, "FetchSleepTime")), waitingListMaxCount: ConfigurationReader.GetValue("TCP:" + ip + ":" + port, "WaitingListCount") != null ? int.Parse(ConfigurationReader.GetValue("TCP:" + ip + ":" + port, "WaitingListCount")) : null));
((BaseConnector)BaseConnector).AddController(new FifoController(int.Parse(ConfigurationReader.GetValue("TCP:" + ip + ":" + port, "FetchSleepTime")), lengthCalc: content => { var ans = 0; for (int i = 9; i < 13; i++) { ans = ans * 10 + (content[i] - 48); } return ans; }, waitingListMaxCount: ConfigurationReader.GetValue("TCP:" + ip + ":" + port, "WaitingListCount") != null ? int.Parse(ConfigurationReader.GetValue("TCP:" + ip + ":" + port, "WaitingListCount")) : null));
}
/// <summary>

View File

@@ -24,7 +24,7 @@ namespace Modbus.Net.Modbus
public ModbusAsciiInUdpProtocolLinker(string ip, int port)
: base(ip, port)
{
((BaseConnector)BaseConnector).AddController(new FifoController(int.Parse(ConfigurationReader.GetValue("UDP:" + ip + ":" + port, "FetchSleepTime")), waitingListMaxCount: ConfigurationReader.GetValue("UDP:" + ip + ":" + port, "WaitingListCount") != null ? int.Parse(ConfigurationReader.GetValue("UDP:" + ip + ":" + port, "WaitingListCount")) : null));
((BaseConnector)BaseConnector).AddController(new FifoController(int.Parse(ConfigurationReader.GetValue("UDP:" + ip + ":" + port, "FetchSleepTime")), lengthCalc: content => { var ans = 0; for (int i = 9; i < 13; i++) { ans = ans * 10 + (content[i] - 48); } return ans; }, waitingListMaxCount: ConfigurationReader.GetValue("UDP:" + ip + ":" + port, "WaitingListCount") != null ? int.Parse(ConfigurationReader.GetValue("UDP:" + ip + ":" + port, "WaitingListCount")) : null));
}
/// <summary>

View File

@@ -16,7 +16,7 @@ namespace Modbus.Net.Modbus
public ModbusAsciiProtocolLinker(string com, int slaveAddress)
: base(com, slaveAddress)
{
((BaseConnector)BaseConnector).AddController(new MatchController(new ICollection<(int, int)>[] { new List<(int, int)> { (1, 1), (2, 2) }, new List<(int, int)> { (3, 3), (4, 4) } }, int.Parse(ConfigurationReader.GetValue("COM:" + com + ":" + slaveAddress, "FetchSleepTime")), waitingListMaxCount: ConfigurationReader.GetValue("COM:" + com + ":" + slaveAddress, "WaitingListCount") != null ? int.Parse(ConfigurationReader.GetValue("COM:" + com + ":" + slaveAddress, "WaitingListCount")) : null));
((BaseConnector)BaseConnector).AddController(new MatchController(new ICollection<(int, int)>[] { new List<(int, int)> { (1, 1), (2, 2) }, new List<(int, int)> { (3, 3), (4, 4) } }, int.Parse(ConfigurationReader.GetValue("COM:" + com + ":" + slaveAddress, "FetchSleepTime")), lengthCalc: content => { var ans = 0; for (int i = 9; i < 13; i++) { ans = ans * 10 + (content[i] - 48); } return ans; }, waitingListMaxCount: ConfigurationReader.GetValue("COM:" + com + ":" + slaveAddress, "WaitingListCount") != null ? int.Parse(ConfigurationReader.GetValue("COM:" + com + ":" + slaveAddress, "WaitingListCount")) : null));
}
/// <summary>

View File

@@ -1,4 +1,6 @@
namespace Modbus.Net.Modbus
using System.Collections.Generic;
namespace Modbus.Net.Modbus
{
/// <summary>
/// Modbus/Rtu协议连接器Tcp透传
@@ -22,7 +24,7 @@
public ModbusRtuInTcpProtocolLinker(string ip, int port)
: base(ip, port)
{
((BaseConnector)BaseConnector).AddController(new FifoController(int.Parse(ConfigurationReader.GetValue("TCP:" + ip + ":" + port, "FetchSleepTime")), waitingListMaxCount: ConfigurationReader.GetValue("TCP:" + ip + ":" + port, "WaitingListCount") != null ? int.Parse(ConfigurationReader.GetValue("TCP:" + ip + ":" + port, "WaitingListCount")) : null));
((BaseConnector)BaseConnector).AddController(new FifoController(int.Parse(ConfigurationReader.GetValue("TCP:" + ip + ":" + port, "FetchSleepTime")), lengthCalc: DuplicateWithCount.GetDuplcateFunc(new List<int> { 2 }, 5), waitingListMaxCount: ConfigurationReader.GetValue("TCP:" + ip + ":" + port, "WaitingListCount") != null ? int.Parse(ConfigurationReader.GetValue("TCP:" + ip + ":" + port, "WaitingListCount")) : null));
}
/// <summary>

View File

@@ -1,4 +1,6 @@
namespace Modbus.Net.Modbus
using System.Collections.Generic;
namespace Modbus.Net.Modbus
{
/// <summary>
/// Modbus/Rtu协议连接器Udp透传
@@ -22,7 +24,7 @@
public ModbusRtuInUdpProtocolLinker(string ip, int port)
: base(ip, port)
{
((BaseConnector)BaseConnector).AddController(new FifoController(int.Parse(ConfigurationReader.GetValue("UDP:" + ip + ":" + port, "FetchSleepTime")), waitingListMaxCount: ConfigurationReader.GetValue("UDP:" + ip + ":" + port, "WaitingListCount") != null ? int.Parse(ConfigurationReader.GetValue("UDP:" + ip + ":" + port, "WaitingListCount")) : null));
((BaseConnector)BaseConnector).AddController(new FifoController(int.Parse(ConfigurationReader.GetValue("UDP:" + ip + ":" + port, "FetchSleepTime")), lengthCalc: DuplicateWithCount.GetDuplcateFunc(new List<int> { 2 }, 5), waitingListMaxCount: ConfigurationReader.GetValue("UDP:" + ip + ":" + port, "WaitingListCount") != null ? int.Parse(ConfigurationReader.GetValue("UDP:" + ip + ":" + port, "WaitingListCount")) : null));
}
/// <summary>

View File

@@ -15,7 +15,7 @@ namespace Modbus.Net.Modbus
public ModbusRtuProtocolLinker(string com, int slaveAddress)
: base(com, slaveAddress)
{
((BaseConnector)BaseConnector).AddController(new MatchController(new ICollection<(int, int)>[] { new List<(int, int)> { (0, 0) }, new List<(int, int)> { (1, 1) } }, int.Parse(ConfigurationReader.GetValue("COM:" + com + ":" + slaveAddress, "FetchSleepTime")), waitingListMaxCount: ConfigurationReader.GetValue("COM:" + com + ":" + slaveAddress, "WaitingListCount") != null ? int.Parse(ConfigurationReader.GetValue("COM:" + com + ":" + slaveAddress, "WaitingListCount")) : null));
((BaseConnector)BaseConnector).AddController(new MatchController(new ICollection<(int, int)>[] { new List<(int, int)> { (0, 0) }, new List<(int, int)> { (1, 1) } }, int.Parse(ConfigurationReader.GetValue("COM:" + com + ":" + slaveAddress, "FetchSleepTime")), lengthCalc: DuplicateWithCount.GetDuplcateFunc(new List<int> { 2 }, 5), waitingListMaxCount: ConfigurationReader.GetValue("COM:" + com + ":" + slaveAddress, "WaitingListCount") != null ? int.Parse(ConfigurationReader.GetValue("COM:" + com + ":" + slaveAddress, "WaitingListCount")) : null));
}
/// <summary>

View File

@@ -1,4 +1,6 @@
namespace Modbus.Net.Modbus
using System.Collections.Generic;
namespace Modbus.Net.Modbus
{
/// <summary>
/// Modbus/Tcp协议连接器
@@ -21,7 +23,7 @@
/// <param name="port">端口</param>
public ModbusTcpProtocolLinker(string ip, int port) : base(ip, port)
{
((BaseConnector)BaseConnector).AddController(new FifoController(int.Parse(ConfigurationReader.GetValue("TCP:" + ip + ":" + port, "FetchSleepTime")), waitingListMaxCount: ConfigurationReader.GetValue("TCP:" + ip + ":" + port, "WaitingListCount") != null ? int.Parse(ConfigurationReader.GetValue("TCP:" + ip + ":" + port, "WaitingListCount")) : null));
((BaseConnector)BaseConnector).AddController(new FifoController(int.Parse(ConfigurationReader.GetValue("TCP:" + ip + ":" + port, "FetchSleepTime")), lengthCalc: DuplicateWithCount.GetDuplcateFunc(new List<int> { 4, 5 }, 6), waitingListMaxCount: ConfigurationReader.GetValue("TCP:" + ip + ":" + port, "WaitingListCount") != null ? int.Parse(ConfigurationReader.GetValue("TCP:" + ip + ":" + port, "WaitingListCount")) : null));
}
/// <summary>

View File

@@ -1,4 +1,6 @@
namespace Modbus.Net.Modbus
using System.Collections.Generic;
namespace Modbus.Net.Modbus
{
/// <summary>
/// Modbus/Udp协议连接器
@@ -21,7 +23,7 @@
/// <param name="port">端口</param>
public ModbusUdpProtocolLinker(string ip, int port) : base(ip, port)
{
((BaseConnector)BaseConnector).AddController(new FifoController(int.Parse(ConfigurationReader.GetValue("UDP:" + ip + ":" + port, "FetchSleepTime")), waitingListMaxCount: ConfigurationReader.GetValue("UDP:" + ip + ":" + port, "WaitingListCount") != null ? int.Parse(ConfigurationReader.GetValue("UDP:" + ip + ":" + port, "WaitingListCount")) : null));
((BaseConnector)BaseConnector).AddController(new FifoController(int.Parse(ConfigurationReader.GetValue("UDP:" + ip + ":" + port, "FetchSleepTime")), lengthCalc: DuplicateWithCount.GetDuplcateFunc(new List<int> { 4, 5 }, 6), waitingListMaxCount: ConfigurationReader.GetValue("UDP:" + ip + ":" + port, "WaitingListCount") != null ? int.Parse(ConfigurationReader.GetValue("UDP:" + ip + ":" + port, "WaitingListCount")) : null));
}
/// <summary>

View File

@@ -1,4 +1,5 @@
using System.Threading;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
@@ -17,7 +18,7 @@ namespace Modbus.Net.Siemens
public SiemensPpiProtocolLinker(string com, int slaveAddress)
: base(com, slaveAddress)
{
((BaseConnector)BaseConnector).AddController(new FifoController(int.Parse(ConfigurationReader.GetValue("COM:" + com + ":" + slaveAddress, "FetchSleepTime")), waitingListMaxCount: ConfigurationReader.GetValue("COM:" + com + ":" + slaveAddress, "WaitingListCount") != null ? int.Parse(ConfigurationReader.GetValue("COM:" + com + ":" + slaveAddress, "WaitingListCount")) : null));
((BaseConnector)BaseConnector).AddController(new FifoController(int.Parse(ConfigurationReader.GetValue("COM:" + com + ":" + slaveAddress, "FetchSleepTime")), lengthCalc: DuplicateWithCount.GetDuplcateFunc(new List<int> { 1 }, 6), waitingListMaxCount: ConfigurationReader.GetValue("COM:" + com + ":" + slaveAddress, "WaitingListCount") != null ? int.Parse(ConfigurationReader.GetValue("COM:" + com + ":" + slaveAddress, "WaitingListCount")) : null));
}
/// <summary>

View File

@@ -83,9 +83,9 @@ namespace Modbus.Net
private bool _taskCancel = false;
/// <summary>
/// Dispose是否执行
/// 缓冲的字节流
/// </summary>
private bool m_disposed;
private List<byte> cachedBytes = new List<byte>();
/// <summary>
/// 构造器
@@ -250,8 +250,6 @@ namespace Modbus.Net
/// </summary>
/// <param name="disposing"></param>
protected virtual void Dispose(bool disposing)
{
if (!m_disposed)
{
if (disposing)
{
@@ -276,8 +274,6 @@ namespace Modbus.Net
Linkers.Remove(_slave);
logger.LogInformation("Com connector {ConnectionToken} Removed", ConnectionToken);
}
m_disposed = true;
}
}
/// <summary>
@@ -484,22 +480,32 @@ namespace Modbus.Net
{
Thread.Sleep(100);
var returnBytes = ReadMsg();
if (returnBytes != null)
{
logger.LogDebug("Com client {ConnectionToken} receive msg length: {Length}", ConnectionToken,
returnBytes.Length);
logger.LogDebug(
$"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);
cachedBytes.AddRange(returnBytes);
var isMessageConfirmed = Controller.ConfirmMessage(cachedBytes.ToArray());
foreach (var confirmed in isMessageConfirmed)
{
if (confirmed.Item2 == false)
{
//主动传输事件
}
cachedBytes.RemoveRange(0, confirmed.Item1.Length);
}
if (isMessageConfirmed.Count > 0 && cachedBytes.Count > 0)
{
logger.LogError("Com client {ConnectionToken} cached msg error: {Length}", ConnectionToken,
cachedBytes.Count);
logger.LogError(
$"Com client {ConnectionToken} cached msg: {string.Concat(cachedBytes.Select(p => " " + p.ToString("X2")))}");
cachedBytes.Clear();
}
RefreshReceiveCount();
}
}

View File

@@ -24,16 +24,16 @@ namespace Modbus.Net
/// <summary>
/// 包切分位置
/// </summary>
protected Func<byte[], ICollection<byte[]>> DuplicateFunc { get; }
protected Func<byte[], int> LengthCalc { get; }
/// <summary>
/// 构造器
/// </summary>
/// <param name="duplicateFunc">包切分函数</param>
protected BaseController(Func<byte[], ICollection<byte[]>> duplicateFunc = null)
/// <param name="lengthCalc">包长度计算函数</param>
protected BaseController(Func<byte[], int> lengthCalc = null)
{
WaitingMessages = new List<MessageWaitingDef>();
DuplicateFunc = duplicateFunc;
LengthCalc = lengthCalc;
}
/// <inheritdoc />
@@ -107,8 +107,22 @@ namespace Modbus.Net
public ICollection<(byte[], bool)> ConfirmMessage(byte[] receiveMessage)
{
var ans = new List<(byte[], bool)>();
var duplicatedMessages = DuplicateFunc?.Invoke(receiveMessage);
duplicatedMessages = duplicatedMessages ?? new List<byte[]> { receiveMessage };
byte[] receiveMessageCopy = new byte[receiveMessage.Length];
Array.Copy(receiveMessage, receiveMessageCopy, receiveMessage.Length);
var length = LengthCalc?.Invoke(receiveMessageCopy);
List<byte[]> duplicatedMessages;
if (length == null) return ans;
else
{
duplicatedMessages = new List<byte[]>();
while (receiveMessageCopy.Length >= length)
{
duplicatedMessages.Add(receiveMessageCopy.Take(length.Value).ToArray());
receiveMessageCopy = receiveMessageCopy.TakeLast(receiveMessage.Length - length.Value).ToArray();
length = LengthCalc?.Invoke(receiveMessageCopy);
if (length == -1) break;
}
}
foreach (var message in duplicatedMessages)
{
var def = GetMessageFromWaitingList(message);
@@ -122,8 +136,11 @@ namespace Modbus.Net
def.ReceiveMutex.Set();
ans.Add((message, true));
}
else
{
ans.Add((message, false));
}
}
return ans;
}

View File

@@ -9,52 +9,32 @@ namespace Modbus.Net
public static class DuplicateWithCount
{
/// <summary>
/// 切分包
/// 计算切分包的长度
/// </summary>
/// <param name="receiveMessage">收到的报文信息</param>
/// <param name="packageCountPositions">收到的断包长度查询位置</param>
/// <param name="otherCount">除掉长度查询信息外其它报文的长度</param>
/// <param name="otherCount">除指示的长度外其它位置的长度</param>
/// <returns>切分后的报文信息</returns>
private static ICollection<byte[]> DuplicateMessages(byte[] receiveMessage, ICollection<int> packageCountPositions, int otherCount)
private static int CalculateLength(byte[] receiveMessage, ICollection<int> packageCountPositions, int otherCount)
{
if (packageCountPositions == null)
return new List<byte[]> { receiveMessage };
var ans = new List<byte[]>();
var pos = 0;
while (pos < receiveMessage.Length)
var ans = 0;
foreach (var position in packageCountPositions)
{
try
{
var length = 0;
foreach (var countPos in packageCountPositions)
{
length = length * 256 + receiveMessage[pos + countPos];
if (position >= receiveMessage.Length) return -1;
ans = ans * 256 + receiveMessage[position];
}
if (length == 0) { break; }
length += otherCount;
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;
return ans + otherCount;
}
/// <summary>
/// 获取按照长度断包的函数
/// 获取长度函数
/// </summary>
/// <param name="packageCountPositions">断包长度的位置信息</param>
/// <param name="otherCount">除掉长度查询信息外其它报文的长度</param>
/// <param name="otherCount">除指示的长度外其它位置的长度</param>
/// <returns>断包函数</returns>
public static Func<byte[], ICollection<byte[]>> GetDuplcateFunc(ICollection<int> packageCountPositions, int otherCount)
public static Func<byte[], int> GetDuplcateFunc(ICollection<int> packageCountPositions, int otherCount)
{
return receiveMessage => DuplicateMessages(receiveMessage, packageCountPositions, otherCount);
return receiveMessage => CalculateLength(receiveMessage, packageCountPositions, otherCount);
}
}
}

View File

@@ -1,6 +1,5 @@
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
@@ -31,10 +30,10 @@ namespace Modbus.Net
/// </summary>
/// <param name="acquireTime">间隔时间</param>
/// <param name="activateSema">是否开启信号量</param>
/// <param name="duplicateFunc">包切分函数</param>
/// <param name="lengthCalc">包切分长度函数</param>
/// <param name="waitingListMaxCount">包等待队列长度</param>
public FifoController(int acquireTime, bool activateSema = true, Func<byte[], ICollection<byte[]>> duplicateFunc = null, int? waitingListMaxCount = null)
: base(duplicateFunc)
public FifoController(int acquireTime, bool activateSema = true, Func<byte[], int> lengthCalc = null, int? waitingListMaxCount = null)
: base(lengthCalc)
{
_waitingListMaxCount = int.Parse(waitingListMaxCount != null ? waitingListMaxCount.ToString() : null ?? ConfigurationReader.GetValueDirect("Controller", "WaitingListCount"));
if (activateSema)

View File

@@ -20,10 +20,10 @@ namespace Modbus.Net
/// <param name="keyMatches">匹配字典每个Collection代表一个匹配集合每一个匹配集合中的数字代表需要匹配的位置最后计算出来的数字是所有位置数字按照集合排序后叠放在一起</param>
/// <param name="acquireTime">获取间隔</param>
/// <param name="activateSema">是否开启信号量</param>
/// <param name="duplicateFunc">包切分函数</param>
/// <param name="lengthCalc">包长度计算</param>
/// <param name="waitingListMaxCount">包等待队列长度</param>
public MatchController(ICollection<(int, int)>[] keyMatches, int acquireTime, bool activateSema = true,
Func<byte[], ICollection<byte[]>> duplicateFunc = null, int? waitingListMaxCount = null) : base(acquireTime, activateSema, duplicateFunc, waitingListMaxCount)
Func<byte[], int> lengthCalc = null, int? waitingListMaxCount = null) : base(acquireTime, activateSema, lengthCalc, waitingListMaxCount)
{
KeyMatches = keyMatches;
}
@@ -38,6 +38,7 @@ namespace Modbus.Net
int tmpCount = 0, tmpCount2 = 0;
foreach (var matchPos in matchPoses)
{
if (matchPos.Item1 >= message.Length || matchPos.Item2 >= message.Length) return null;
tmpCount = tmpCount * 256 + message[matchPos.Item1];
tmpCount2 = tmpCount2 * 256 + message[matchPos.Item2];
}

View File

@@ -10,8 +10,8 @@ namespace Modbus.Net
{
/// <inheritdoc />
public MatchDirectlySendController(ICollection<(int, int)>[] keyMatches,
Func<byte[], ICollection<byte[]>> duplicateFunc = null, int? waitingListMaxCount = null) : base(keyMatches,
0, false, duplicateFunc, waitingListMaxCount)
Func<byte[], int> lengthCalc = null, int? waitingListMaxCount = null) : base(keyMatches,
0, false, lengthCalc, waitingListMaxCount)
{
}

View File

@@ -5,7 +5,7 @@ using Serilog;
var configuration = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json")
.AddJsonFile($"appsettings.{Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") ?? "Production"}.json", true)
.AddJsonFile($"appsettings.{Environment.GetEnvironmentVariable("DOTNET_ENVIRONMENT") ?? "Production"}.json", true)
.Build();
Log.Logger = new LoggerConfiguration()

View File

@@ -1,8 +1,7 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.Hosting.Lifetime": "Information"
"Serilog": {
"MinimumLevel": {
"Default": "Information"
}
}
}