Fix Bugs in modbus rtu

This commit is contained in:
luosheng
2023-03-22 11:33:59 +08:00
parent 970deb48be
commit ef47a1be06
10 changed files with 86 additions and 59 deletions

View File

@@ -24,7 +24,7 @@ namespace Modbus.Net.Modbus
public ModbusAsciiInTcpProtocolLinker(string ip, int port) public ModbusAsciiInTcpProtocolLinker(string ip, int port)
: base(ip, port) : base(ip, port)
{ {
((BaseConnector)BaseConnector).AddController(new FifoController(int.Parse(ConfigurationReader.GetValue("TCP:" + ip + ":" + port, "FetchSleepTime")), lengthCalc: content => { if (content[0] != 0x3a) return -1; for (int i = 1; i < content.Length; i++) { if (content[i - 1] == 0x0D && content[i] == 0x0A) return i + 1; } return -1; }, 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 => { if (content[0] != 0x3a) return 0; for (int i = 1; i < content.Length; i++) { if (content[i - 1] == 0x0D && content[i] == 0x0A) return i + 1; } return -1; }, waitingListMaxCount: ConfigurationReader.GetValue("TCP:" + ip + ":" + port, "WaitingListCount") != null ? int.Parse(ConfigurationReader.GetValue("TCP:" + ip + ":" + port, "WaitingListCount")) : null));
} }
/// <summary> /// <summary>

View File

@@ -24,7 +24,7 @@ namespace Modbus.Net.Modbus
public ModbusAsciiInUdpProtocolLinker(string ip, int port) public ModbusAsciiInUdpProtocolLinker(string ip, int port)
: base(ip, port) : base(ip, port)
{ {
((BaseConnector)BaseConnector).AddController(new FifoController(int.Parse(ConfigurationReader.GetValue("UDP:" + ip + ":" + port, "FetchSleepTime")), lengthCalc: content => { if (content[0] != 0x3a) return -1; for (int i = 1; i < content.Length; i++) { if (content[i - 1] == 0x0D && content[i] == 0x0A) return i + 1; } return -1; }, 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 => { if (content[0] != 0x3a) return 0; for (int i = 1; i < content.Length; i++) { if (content[i - 1] == 0x0D && content[i] == 0x0A) return i + 1; } return -1; }, waitingListMaxCount: ConfigurationReader.GetValue("UDP:" + ip + ":" + port, "WaitingListCount") != null ? int.Parse(ConfigurationReader.GetValue("UDP:" + ip + ":" + port, "WaitingListCount")) : null));
} }
/// <summary> /// <summary>

View File

@@ -16,7 +16,7 @@ namespace Modbus.Net.Modbus
public ModbusAsciiProtocolLinker(string com, int slaveAddress) public ModbusAsciiProtocolLinker(string com, int slaveAddress)
: base(com, 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")), lengthCalc: content => { if (content[0] != 0x3a) return -1; for (int i = 1; i < content.Length; i++) { if (content[i - 1] == 0x0D && content[i] == 0x0A) return i + 1; } return -1; }, 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 => { if (content[0] != 0x3a) return 0; for (int i = 1; i < content.Length; i++) { if (content[i - 1] == 0x0D && content[i] == 0x0A) return i + 1; } return -1; }, waitingListMaxCount: ConfigurationReader.GetValue("COM:" + com + ":" + slaveAddress, "WaitingListCount") != null ? int.Parse(ConfigurationReader.GetValue("COM:" + com + ":" + slaveAddress, "WaitingListCount")) : null));
} }
/// <summary> /// <summary>

View File

@@ -24,7 +24,7 @@ namespace Modbus.Net.Modbus
public ModbusRtuInTcpProtocolLinker(string ip, int port) public ModbusRtuInTcpProtocolLinker(string ip, int port)
: base(ip, port) : base(ip, port)
{ {
((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)); ((BaseConnector)BaseConnector).AddController(new FifoController(int.Parse(ConfigurationReader.GetValue("TCP:" + ip + ":" + port, "FetchSleepTime")), lengthCalc: content => { if (content[1] == 5 || content[1] == 6 || content[1] == 15 || content[1] == 16 || content[1] == 21) return 8; else return DuplicateWithCount.GetDuplcateFunc(new List<int> { 2 }, 5).Invoke(content); }, waitingListMaxCount: ConfigurationReader.GetValue("TCP:" + ip + ":" + port, "WaitingListCount") != null ? int.Parse(ConfigurationReader.GetValue("TCP:" + ip + ":" + port, "WaitingListCount")) : null));
} }
/// <summary> /// <summary>

View File

@@ -24,7 +24,7 @@ namespace Modbus.Net.Modbus
public ModbusRtuInUdpProtocolLinker(string ip, int port) public ModbusRtuInUdpProtocolLinker(string ip, int port)
: base(ip, port) : base(ip, port)
{ {
((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)); ((BaseConnector)BaseConnector).AddController(new FifoController(int.Parse(ConfigurationReader.GetValue("UDP:" + ip + ":" + port, "FetchSleepTime")), lengthCalc: content => { if (content[1] == 5 || content[1] == 6 || content[1] == 15 || content[1] == 16 || content[1] == 21) return 8; else return DuplicateWithCount.GetDuplcateFunc(new List<int> { 2 }, 5).Invoke(content); }, waitingListMaxCount: ConfigurationReader.GetValue("UDP:" + ip + ":" + port, "WaitingListCount") != null ? int.Parse(ConfigurationReader.GetValue("UDP:" + ip + ":" + port, "WaitingListCount")) : null));
} }
/// <summary> /// <summary>

View File

@@ -15,7 +15,7 @@ namespace Modbus.Net.Modbus
public ModbusRtuProtocolLinker(string com, int slaveAddress) public ModbusRtuProtocolLinker(string com, int slaveAddress)
: base(com, 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")), 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)); ((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: content => { if (content[1] == 5 || content[1] == 6 || content[1] == 15 || content[1] == 16 || content[1] == 21) return 8; else return DuplicateWithCount.GetDuplcateFunc(new List<int> { 2 }, 5).Invoke(content); }, waitingListMaxCount: ConfigurationReader.GetValue("COM:" + com + ":" + slaveAddress, "WaitingListCount") != null ? int.Parse(ConfigurationReader.GetValue("COM:" + com + ":" + slaveAddress, "WaitingListCount")) : null));
} }
/// <summary> /// <summary>

View File

@@ -85,7 +85,19 @@ namespace Modbus.Net
/// <summary> /// <summary>
/// 缓冲的字节流 /// 缓冲的字节流
/// </summary> /// </summary>
private List<byte> _cachedBytes = new List<byte>(); private static Dictionary<string, List<byte>> _cachedBytes = new Dictionary<string, List<byte>>();
private List<byte> CacheBytes
{
get
{
if (!_cachedBytes.ContainsKey(_com))
{
_cachedBytes.Add(_com, new List<byte>());
}
return _cachedBytes[_com];
}
}
/// <summary> /// <summary>
/// 构造器 /// 构造器
@@ -151,12 +163,12 @@ namespace Modbus.Net
/// <summary> /// <summary>
/// 连接中的连接器 /// 连接中的连接器
/// </summary> /// </summary>
private static Dictionary<string, string> Linkers { get; } = new Dictionary<string, string>(); private static HashSet<(string, string)> Linkers { get; } = new HashSet<(string, string)>();
/// <summary> /// <summary>
/// 连接关键字(串口号:从站号) /// 连接关键字(串口号:从站号)
/// </summary> /// </summary>
public override string ConnectionToken => _slave + ":" + _com; public override string ConnectionToken => _com + ":" + _slave;
/// <summary> /// <summary>
/// 获取当前连接器使用的串口 /// 获取当前连接器使用的串口
@@ -254,12 +266,13 @@ namespace Modbus.Net
if (disposing) if (disposing)
{ {
// Release managed resources // Release managed resources
Controller.SendStop();
} }
// Release unmanaged resources // Release unmanaged resources
if (SerialPort != null) if (SerialPort != null)
{ {
if (Linkers.Values.Count(p => p == _com) <= 1) Linkers.Remove((_slave, _com));
logger.LogInformation("Com connector {ConnectionToken} Removed", _com);
if (Linkers.Count(p => p.Item2 == _com) == 0)
{ {
if (SerialPort.IsOpen) if (SerialPort.IsOpen)
{ {
@@ -267,12 +280,12 @@ namespace Modbus.Net
} }
SerialPort.Dispose(); SerialPort.Dispose();
logger.LogInformation("Com interface {Com} Disposed", _com); logger.LogInformation("Com interface {Com} Disposed", _com);
Controller.SendStop();
Controllers.Remove(_com);
Connectors[_com] = null; Connectors[_com] = null;
Connectors.Remove(_com); Connectors.Remove(_com);
ReceiveMsgThreadStop(); ReceiveMsgThreadStop();
} }
Linkers.Remove(_slave);
logger.LogInformation("Com connector {ConnectionToken} Removed", ConnectionToken);
} }
} }
@@ -294,13 +307,13 @@ namespace Modbus.Net
private void RefreshReceiveCount() private void RefreshReceiveCount()
{ {
_receiveCount++; _receiveCount++;
logger.LogDebug("Com client {ConnectionToken} receive count: {SendCount}", ConnectionToken, _receiveCount); logger.LogDebug("Com client {ConnectionToken} receive count: {SendCount}", _com, _receiveCount);
} }
private void RefreshErrorCount() private void RefreshErrorCount()
{ {
_errorCount++; _errorCount++;
logger.LogDebug("Com client {ConnectionToken} error count: {ErrorCount}", ConnectionToken, _errorCount); logger.LogDebug("Com client {ConnectionToken} error count: {ErrorCount}", _com, _errorCount);
} }
/// <inheritdoc /> /// <inheritdoc />
@@ -310,7 +323,7 @@ namespace Modbus.Net
{ {
if (SerialPort != null && !SerialPort.IsOpen) if (SerialPort != null && !SerialPort.IsOpen)
SerialPort.Dispose(); SerialPort.Dispose();
return SerialPort != null && SerialPort.IsOpen && Linkers.ContainsKey(_slave); return SerialPort != null && SerialPort.IsOpen && Linkers.Contains((_slave, _com));
} }
} }
@@ -336,9 +349,9 @@ namespace Modbus.Net
ReadTimeout = TimeoutTime ReadTimeout = TimeoutTime
}); });
} }
if (!Linkers.ContainsKey(_slave)) if (!Linkers.Contains((_slave, _com)))
{ {
Linkers.Add(_slave, _com); Linkers.Add((_slave, _com));
} }
if (!SerialPort.IsOpen) if (!SerialPort.IsOpen)
{ {
@@ -352,13 +365,13 @@ namespace Modbus.Net
} }
} }
logger.LogInformation("Com client {ConnectionToken} connect success", ConnectionToken); logger.LogInformation("Com client {ConnectionToken} connect success", _com);
return true; return true;
} }
catch (Exception e) catch (Exception e)
{ {
logger.LogError(e, "Com client {ConnectionToken} connect error", ConnectionToken); logger.LogError(e, "Com client {ConnectionToken} connect error", _com);
Dispose(); Dispose();
return false; return false;
} }
@@ -373,7 +386,7 @@ namespace Modbus.Net
/// <inheritdoc /> /// <inheritdoc />
public override bool Disconnect() public override bool Disconnect()
{ {
if (Linkers.ContainsKey(_slave) && Connectors.ContainsKey(_com)) if (Linkers.Contains((_slave, _com)) && Connectors.ContainsKey(_com))
try try
{ {
Dispose(); Dispose();
@@ -419,7 +432,7 @@ namespace Modbus.Net
} }
catch (Exception err) catch (Exception err)
{ {
logger.LogError(err, "Com client {ConnectionToken} open error", ConnectionToken); logger.LogError(err, "Com client {ConnectionToken} open error", _com);
Dispose(); Dispose();
try try
{ {
@@ -427,7 +440,7 @@ namespace Modbus.Net
} }
catch (Exception err2) catch (Exception err2)
{ {
logger.LogError(err2, "Com client {ConnectionToken} open error", ConnectionToken); logger.LogError(err2, "Com client {ConnectionToken} open error", _com);
Dispose(); Dispose();
} }
} }
@@ -463,7 +476,7 @@ namespace Modbus.Net
/// <inheritdoc /> /// <inheritdoc />
protected override void ReceiveMsgThreadStart() protected override void ReceiveMsgThreadStart()
{ {
_receiveThread = Task.Run(() => ReceiveMessage()); _receiveThread = Task.Run(ReceiveMessage);
} }
/// <inheritdoc /> /// <inheritdoc />
@@ -483,36 +496,42 @@ namespace Modbus.Net
if (returnBytes != null) if (returnBytes != null)
{ {
logger.LogDebug("Com client {ConnectionToken} receive msg length: {Length}", ConnectionToken, logger.LogDebug("Com client {ConnectionToken} receive msg length: {Length}", _com,
returnBytes.Length); returnBytes.Length);
logger.LogDebug( logger.LogDebug(
$"Com client {ConnectionToken} receive msg: {string.Concat(returnBytes.Select(p => " " + p.ToString("X2")))}"); $"Com client {_com} receive msg: {string.Concat(returnBytes.Select(p => " " + p.ToString("X2")))}");
lock (_cachedBytes) lock (CacheBytes)
{ {
_cachedBytes.AddRange(returnBytes); CacheBytes.AddRange(returnBytes);
} }
var isMessageConfirmed = Controller.ConfirmMessage(_cachedBytes.ToArray()); var isMessageConfirmed = Controller.ConfirmMessage(CacheBytes.ToArray());
foreach (var confirmed in isMessageConfirmed) if (isMessageConfirmed == null)
{
if (confirmed.Item2 == false)
{
//主动传输事件
}
lock (_cachedBytes)
{
_cachedBytes.RemoveRange(0, confirmed.Item1.Length);
}
}
if (isMessageConfirmed.Count > 0 && _cachedBytes.Count > 0)
{ {
logger.LogError("Com client {ConnectionToken} cached msg error: {Length}", ConnectionToken, logger.LogError("Com client {ConnectionToken} cached msg error: {Length}", ConnectionToken,
_cachedBytes.Count); CacheBytes.Count);
logger.LogError( logger.LogError(
$"Com client {ConnectionToken} cached msg: {string.Concat(_cachedBytes.Select(p => " " + p.ToString("X2")))}"); $"Com client {ConnectionToken} cached msg: {string.Concat(CacheBytes.Select(p => " " + p.ToString("X2")))}");
lock (_cachedBytes) lock (CacheBytes)
{ {
_cachedBytes.Clear(); CacheBytes.Clear();
}
}
else
{
foreach (var confirmed in isMessageConfirmed)
{
if (confirmed.Item2)
{
lock (CacheBytes)
{
CacheBytes.RemoveRange(0, confirmed.Item1.Length);
}
}
else if (confirmed.Item2 == false)
{
//主动传输事件
}
} }
} }
RefreshReceiveCount(); RefreshReceiveCount();
@@ -542,7 +561,7 @@ namespace Modbus.Net
} }
catch (Exception e) catch (Exception e)
{ {
logger.LogError(e, "Com client {ConnectionToken} read error", ConnectionToken); logger.LogError(e, "Com client {ConnectionToken} read error", _com);
RefreshErrorCount(); RefreshErrorCount();
Dispose(); Dispose();
return null; return null;

View File

@@ -236,15 +236,18 @@ namespace Modbus.Net
logger.LogDebug( logger.LogDebug(
$"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);
foreach (var confirmed in isMessageConfirmed) if (isMessageConfirmed != null)
{ {
if (confirmed.Item2 == false) foreach (var confirmed in isMessageConfirmed)
{ {
var sendMessage = InvokeReturnMessage(confirmed.Item1); if (confirmed.Item2 == false)
//主动传输事件
if (sendMessage != null)
{ {
await SendMsgWithoutConfirm(sendMessage); var sendMessage = InvokeReturnMessage(confirmed.Item1);
//主动传输事件
if (sendMessage != null)
{
await SendMsgWithoutConfirm(sendMessage);
}
} }
} }
} }

View File

@@ -217,15 +217,18 @@ namespace Modbus.Net
logger.LogDebug( logger.LogDebug(
$"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);
foreach (var confirmed in isMessageConfirmed) if (isMessageConfirmed != null)
{ {
if (confirmed.Item2 == false) foreach (var confirmed in isMessageConfirmed)
{ {
var sendMessage = InvokeReturnMessage(confirmed.Item1); if (confirmed.Item2 == false)
//主动传输事件
if (sendMessage != null)
{ {
await SendMsgWithoutConfirm(sendMessage); var sendMessage = InvokeReturnMessage(confirmed.Item1);
//主动传输事件
if (sendMessage != null)
{
await SendMsgWithoutConfirm(sendMessage);
}
} }
} }
} }

View File

@@ -112,6 +112,7 @@ namespace Modbus.Net
var length = LengthCalc?.Invoke(receiveMessageCopy); var length = LengthCalc?.Invoke(receiveMessageCopy);
List<byte[]> duplicatedMessages; List<byte[]> duplicatedMessages;
if (length == null || length == -1) return ans; if (length == null || length == -1) return ans;
if (length == 0) return null;
else else
{ {
duplicatedMessages = new List<byte[]>(); duplicatedMessages = new List<byte[]>();
@@ -122,6 +123,7 @@ namespace Modbus.Net
if (receiveMessageCopy.Length == 0) break; if (receiveMessageCopy.Length == 0) break;
length = LengthCalc?.Invoke(receiveMessageCopy); length = LengthCalc?.Invoke(receiveMessageCopy);
if (length == -1) break; if (length == -1) break;
if (length == 0) return null;
} }
} }
foreach (var message in duplicatedMessages) foreach (var message in duplicatedMessages)