Code optimization and controller enchancement
This commit is contained in:
@@ -0,0 +1,158 @@
|
||||
using Microsoft.CodeAnalysis;
|
||||
using System.Text;
|
||||
|
||||
namespace Modbus.Net.CodeGenerator
|
||||
{
|
||||
[Generator]
|
||||
public class BaseConnectorCodeGenerator : ISourceGenerator
|
||||
{
|
||||
public void Execute(GeneratorExecutionContext context)
|
||||
{
|
||||
var source = $@"
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Nito.AsyncEx;
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Modbus.Net
|
||||
{{
|
||||
public abstract partial class BaseConnector : BaseConnector<byte[], byte[]>
|
||||
{{
|
||||
"
|
||||
+ ConnectorWithControllerByteArrayCodeContent.Code("BaseConnector")
|
||||
+ $@"
|
||||
}}
|
||||
}}";
|
||||
context.AddSource("BaseConnectorContent.g.cs", source);
|
||||
}
|
||||
|
||||
public void Initialize(GeneratorInitializationContext context)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
[Generator]
|
||||
public class EventHandlerConnectorCodeGenerator : ISourceGenerator
|
||||
{
|
||||
public void Execute(GeneratorExecutionContext context)
|
||||
{
|
||||
var source = $@"
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Nito.AsyncEx;
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Modbus.Net
|
||||
{{
|
||||
public abstract partial class EventHandlerConnector : EventHandlerConnector<byte[], byte[]>
|
||||
{{
|
||||
"
|
||||
+ ConnectorWithControllerByteArrayCodeContent.Code("EventHandlerConnector")
|
||||
+ $@"
|
||||
}}
|
||||
}}";
|
||||
context.AddSource("EventHandlerConnectorContent.g.cs", source);
|
||||
}
|
||||
|
||||
public void Initialize(GeneratorInitializationContext context)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public static class ConnectorWithControllerByteArrayCodeContent
|
||||
{
|
||||
public static string Code(string className)
|
||||
{
|
||||
return new StringBuilder(@"
|
||||
/// <summary>
|
||||
/// 发送锁
|
||||
/// </summary>
|
||||
protected abstract AsyncLock Lock { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否为全双工
|
||||
/// </summary>
|
||||
public bool IsFullDuplex { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 发送超时时间
|
||||
/// </summary>
|
||||
protected abstract int TimeoutTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 构造器
|
||||
/// </summary>
|
||||
/// <param name=""timeoutTime"">发送超时时间</param>
|
||||
/// <param name=""isFullDuplex"">是否为全双工</param>
|
||||
protected {%0}(int timeoutTime = 10000, bool isFullDuplex = false)
|
||||
{
|
||||
IsFullDuplex = isFullDuplex;
|
||||
if (timeoutTime < -1) timeoutTime = -1;
|
||||
TimeoutTime = timeoutTime;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override async Task<byte[]> SendMsgAsync(byte[] message)
|
||||
{
|
||||
var ans = await SendMsgInner(message);
|
||||
if (ans == null) return new byte[0];
|
||||
return ans.ReceiveMessage;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 发送内部
|
||||
/// </summary>
|
||||
/// <param name=""message"">发送的信息</param>
|
||||
/// <param name=""repeat"">是否为重发消息</param>
|
||||
/// <returns>发送信息的定义</returns>
|
||||
protected async Task<MessageWaitingDef> SendMsgInner(byte[] message, bool repeat = false)
|
||||
{
|
||||
IDisposable asyncLock = null;
|
||||
try
|
||||
{
|
||||
if (!Controller.IsSending)
|
||||
{
|
||||
Controller.SendStart();
|
||||
}
|
||||
var messageSendingdef = Controller.AddMessage(message);
|
||||
if (messageSendingdef != null)
|
||||
{
|
||||
if (!IsFullDuplex)
|
||||
{
|
||||
asyncLock = await Lock.LockAsync();
|
||||
}
|
||||
var success = messageSendingdef.SendMutex.WaitOne(TimeoutTime);
|
||||
if (success)
|
||||
{
|
||||
await SendMsgWithoutConfirm(message);
|
||||
success = messageSendingdef.ReceiveMutex.WaitOne(TimeoutTime);
|
||||
if (success)
|
||||
{
|
||||
if (!repeat && messageSendingdef.ReceiveMessage == null)
|
||||
{
|
||||
asyncLock?.Dispose();
|
||||
return await SendMsgInner(message, true);
|
||||
}
|
||||
return messageSendingdef;
|
||||
}
|
||||
}
|
||||
Controller.ForceRemoveWaitingMessage(messageSendingdef);
|
||||
}
|
||||
logger.LogInformation(""Message is waiting in {0}. Cancel!"", ConnectionToken);
|
||||
return null;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
logger.LogError(e, ""Connector {0} Send Error."", ConnectionToken);
|
||||
return null;
|
||||
}
|
||||
finally
|
||||
{
|
||||
asyncLock?.Dispose();
|
||||
}
|
||||
}").Replace("{%0}", className).ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Library</OutputType>
|
||||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
<LangVersion>9.0</LangVersion>
|
||||
<EnforceExtendedAnalyzerRules>true</EnforceExtendedAnalyzerRules>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.6.0" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
10
Modbus.Net/Modbus.Net.HJ212/HJ212Controller.cs
Normal file
10
Modbus.Net/Modbus.Net.HJ212/HJ212Controller.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
namespace Modbus.Net.HJ212
|
||||
{
|
||||
public class HJ212Controller : FifoController
|
||||
{
|
||||
public HJ212Controller(string ip, int port) : base(int.Parse(ConfigurationReader.GetValue("TCP:" + ip + ":" + port, "FetchSleepTime")))
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -27,7 +27,6 @@ namespace Modbus.Net.HJ212
|
||||
/// </summary>
|
||||
/// <param name="id">设备的ID号</param>
|
||||
/// <param name="connectionString">连接地址</param>
|
||||
/// <param name="getAddresses">需要读写的地址</param>
|
||||
public HJ212Machine(TKey id, string connectionString, string st, string cn, string pw, string mn)
|
||||
: base(id, null, true)
|
||||
{
|
||||
|
||||
@@ -13,10 +13,10 @@ namespace Modbus.Net.HJ212
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
public HJ212Protocol(string connectionToken)
|
||||
public HJ212Protocol(string ip)
|
||||
: base(0, 0, Endian.BigEndianLsb)
|
||||
{
|
||||
ProtocolLinker = new HJ212ProtocolLinker(connectionToken);
|
||||
ProtocolLinker = new HJ212ProtocolLinker(ip, int.Parse(ConfigurationReader.GetValueDirect("TCP:" + ip, "HJ212Port") ?? ConfigurationReader.GetValueDirect("TCP:Modbus", "HJ212Port") ?? "443"));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -3,12 +3,10 @@
|
||||
/// <summary>
|
||||
/// HJ212协议连接器
|
||||
/// </summary>
|
||||
public class HJ212ProtocolLinker : ProtocolLinker
|
||||
public class HJ212ProtocolLinker : TcpProtocolLinker
|
||||
{
|
||||
public HJ212ProtocolLinker(string connectionToken)
|
||||
public HJ212ProtocolLinker(string ip, int port) : base(ip, port)
|
||||
{
|
||||
BaseConnector = new TcpConnector(connectionToken, 443);
|
||||
((IConnectorWithController<byte[], byte[]>)BaseConnector).AddController(new FifoController(1000));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -24,21 +24,6 @@ namespace Modbus.Net.Modbus
|
||||
public ModbusAsciiInTcpProtocolLinker(string ip, int port)
|
||||
: base(ip, port)
|
||||
{
|
||||
((IConnectorWithController<byte[], byte[]>)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;
|
||||
},
|
||||
checkRightFunc: ContentCheck.LrcCheckRight,
|
||||
waitingListMaxCount: ConfigurationReader.GetValue("TCP:" + ip + ":" + port, "WaitingListCount") != null
|
||||
? int.Parse(ConfigurationReader.GetValue("TCP:" + ip + ":" + port, "WaitingListCount"))
|
||||
: null
|
||||
));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -24,22 +24,6 @@ namespace Modbus.Net.Modbus
|
||||
public ModbusAsciiInUdpProtocolLinker(string ip, int port)
|
||||
: base(ip, port)
|
||||
{
|
||||
((IConnectorWithController<byte[], byte[]>)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;
|
||||
},
|
||||
checkRightFunc: ContentCheck.LrcCheckRight,
|
||||
waitingListMaxCount: ConfigurationReader.GetValue("UDP:" + ip + ":" + port, "WaitingListCount") != null
|
||||
? int.Parse(ConfigurationReader.GetValue("UDP:" + ip + ":" + port, "WaitingListCount"))
|
||||
: null
|
||||
));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -15,22 +15,6 @@ namespace Modbus.Net.Modbus
|
||||
public ModbusAsciiProtocolLinker(string com, int slaveAddress)
|
||||
: base(com, slaveAddress)
|
||||
{
|
||||
((IConnectorWithController<byte[], byte[]>)BaseConnector).AddController(new FifoController(
|
||||
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;
|
||||
},
|
||||
checkRightFunc: ContentCheck.LrcCheckRight,
|
||||
waitingListMaxCount: ConfigurationReader.GetValue("COM:" + com + ":" + slaveAddress, "WaitingListCount") != null ?
|
||||
int.Parse(ConfigurationReader.GetValue("COM:" + com + ":" + slaveAddress, "WaitingListCount")) :
|
||||
null
|
||||
));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
238
Modbus.Net/Modbus.Net.Modbus/ModbusController.cs
Normal file
238
Modbus.Net/Modbus.Net.Modbus/ModbusController.cs
Normal file
@@ -0,0 +1,238 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Modbus.Net.Modbus
|
||||
{
|
||||
/// <summary>
|
||||
/// Modbus长度计算
|
||||
/// </summary>
|
||||
public static class ModbusLengthCalc
|
||||
{
|
||||
/// <summary>
|
||||
/// Modbus Ascii协议长度计算
|
||||
/// </summary>
|
||||
public static Func<byte[], int> ModbusAsciiLengthCalc => 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;
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Modbus Rtu协议长度计算
|
||||
/// </summary>
|
||||
public static Func<byte[], int> ModbusRtuLengthCalc => content =>
|
||||
{
|
||||
if (content[1] > 128) return 5;
|
||||
else if (content[1] == 5 || content[1] == 6 || content[1] == 8 || content[1] == 11 || content[1] == 15 || content[1] == 16) return 8;
|
||||
else if (content[1] == 7) return 5;
|
||||
else if (content[1] == 22) return 10;
|
||||
else return DuplicateWithCount.GetDuplcateFunc(new List<int> { 2 }, 5).Invoke(content);
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Modbus Ascii协议控制器
|
||||
/// </summary>
|
||||
public class ModbusAsciiController : FifoController
|
||||
{
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
/// <param name="com">串口</param>
|
||||
/// <param name="slaveAddress">从站号</param>
|
||||
public ModbusAsciiController(string com, int slaveAddress) : base(
|
||||
int.Parse(ConfigurationReader.GetValue("COM:" + com + ":" + slaveAddress, "FetchSleepTime")),
|
||||
lengthCalc: ModbusLengthCalc.ModbusAsciiLengthCalc,
|
||||
checkRightFunc: ContentCheck.LrcCheckRight,
|
||||
waitingListMaxCount: ConfigurationReader.GetValue("COM:" + com + ":" + slaveAddress, "WaitingListCount") != null ?
|
||||
int.Parse(ConfigurationReader.GetValue("COM:" + com + ":" + slaveAddress, "WaitingListCount")) :
|
||||
null
|
||||
)
|
||||
{ }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Modbus Ascii in Tcp协议控制器
|
||||
/// </summary>
|
||||
public class ModbusAsciiInTcpController : FifoController
|
||||
{
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
/// <param name="ip">ip地址</param>
|
||||
/// <param name="port">端口号</param>
|
||||
public ModbusAsciiInTcpController(string ip, int port) : base(int.Parse(ConfigurationReader.GetValue("TCP:" + ip + ":" + port, "FetchSleepTime")),
|
||||
lengthCalc: ModbusLengthCalc.ModbusAsciiLengthCalc,
|
||||
checkRightFunc: ContentCheck.LrcCheckRight,
|
||||
waitingListMaxCount: ConfigurationReader.GetValue("TCP:" + ip + ":" + port, "WaitingListCount") != null
|
||||
? int.Parse(ConfigurationReader.GetValue("TCP:" + ip + ":" + port, "WaitingListCount"))
|
||||
: null
|
||||
)
|
||||
{ }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Modbus Ascii in Udp协议控制器
|
||||
/// </summary>
|
||||
public class ModbusAsciiInUdpController : FifoController
|
||||
{
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
/// <param name="ip">ip地址</param>
|
||||
/// <param name="port">端口号</param>
|
||||
public ModbusAsciiInUdpController(string ip, int port) : base(int.Parse(ConfigurationReader.GetValue("UDP:" + ip + ":" + port, "FetchSleepTime")),
|
||||
lengthCalc: ModbusLengthCalc.ModbusAsciiLengthCalc,
|
||||
checkRightFunc: ContentCheck.LrcCheckRight,
|
||||
waitingListMaxCount: ConfigurationReader.GetValue("UDP:" + ip + ":" + port, "WaitingListCount") != null
|
||||
? int.Parse(ConfigurationReader.GetValue("UDP:" + ip + ":" + port, "WaitingListCount"))
|
||||
: null
|
||||
)
|
||||
{ }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Modbus Rtu协议控制器
|
||||
/// </summary>
|
||||
public class ModbusRtuController : FifoController
|
||||
{
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
/// <param name="com">串口</param>
|
||||
/// <param name="slaveAddress">从站号</param>
|
||||
public ModbusRtuController(string com, int slaveAddress) : base(
|
||||
int.Parse(ConfigurationReader.GetValue("COM:" + com + ":" + slaveAddress, "FetchSleepTime")),
|
||||
lengthCalc: ModbusLengthCalc.ModbusRtuLengthCalc,
|
||||
checkRightFunc: ContentCheck.Crc16CheckRight,
|
||||
waitingListMaxCount: ConfigurationReader.GetValue("COM:" + com + ":" + slaveAddress, "WaitingListCount") != null ?
|
||||
int.Parse(ConfigurationReader.GetValue("COM:" + com + ":" + slaveAddress, "WaitingListCount")) :
|
||||
null
|
||||
)
|
||||
{ }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Modbus Rtu in Tcp协议控制器
|
||||
/// </summary>
|
||||
public class ModbusRtuInTcpController : FifoController
|
||||
{
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
/// <param name="ip">ip地址</param>
|
||||
/// <param name="port">端口号</param>
|
||||
public ModbusRtuInTcpController(string ip, int port) : base(
|
||||
int.Parse(ConfigurationReader.GetValue("TCP:" + ip + ":" + port, "FetchSleepTime")),
|
||||
lengthCalc: ModbusLengthCalc.ModbusRtuLengthCalc,
|
||||
checkRightFunc: ContentCheck.Crc16CheckRight,
|
||||
waitingListMaxCount: ConfigurationReader.GetValue("TCP:" + ip + ":" + port, "WaitingListCount") != null ?
|
||||
int.Parse(ConfigurationReader.GetValue("TCP:" + ip + ":" + port, "WaitingListCount")) :
|
||||
null
|
||||
)
|
||||
{ }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Modbus Rtu in Udp协议控制器
|
||||
/// </summary>
|
||||
public class ModbusRtuInUdpController : FifoController
|
||||
{
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
/// <param name="ip">ip地址</param>
|
||||
/// <param name="port">端口号</param>
|
||||
public ModbusRtuInUdpController(string ip, int port) : base(
|
||||
int.Parse(ConfigurationReader.GetValue("UDP:" + ip + ":" + port, "FetchSleepTime")),
|
||||
lengthCalc: ModbusLengthCalc.ModbusRtuLengthCalc,
|
||||
checkRightFunc: ContentCheck.Crc16CheckRight,
|
||||
waitingListMaxCount: ConfigurationReader.GetValue("UDP:" + ip + ":" + port, "WaitingListCount") != null ?
|
||||
int.Parse(ConfigurationReader.GetValue("UDP:" + ip + ":" + port, "WaitingListCount")) :
|
||||
null
|
||||
)
|
||||
{ }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Modbus Tcp协议控制器
|
||||
/// </summary>
|
||||
public class ModbusTcpController : ModbusEthMatchDirectlySendController
|
||||
{
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
/// <param name="ip">ip地址</param>
|
||||
/// <param name="port">端口号</param>
|
||||
public ModbusTcpController(string ip, int port) : base(
|
||||
new ICollection<(int, int)>[] { new List<(int, int)> { (0, 0), (1, 1) } },
|
||||
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>
|
||||
/// Modbus Udp协议控制器
|
||||
/// </summary>
|
||||
public class ModbusUdpController : ModbusEthMatchDirectlySendController
|
||||
{
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
/// <param name="ip">ip地址</param>
|
||||
/// <param name="port">端口号</param>
|
||||
public ModbusUdpController(string ip, int port) : base(
|
||||
new ICollection<(int, int)>[] { new List<(int, int)> { (0, 0), (1, 1) } },
|
||||
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>
|
||||
/// 匹配控制器,载入队列后直接发送
|
||||
/// </summary>
|
||||
public class ModbusEthMatchDirectlySendController : MatchDirectlySendController
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public ModbusEthMatchDirectlySendController(ICollection<(int, int)>[] keyMatches,
|
||||
Func<byte[], int> lengthCalc = null, Func<byte[], bool?> checkRightFunc = null, int? waitingListMaxCount = null) : base(keyMatches,
|
||||
lengthCalc, checkRightFunc, waitingListMaxCount)
|
||||
{
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override MessageWaitingDef GetMessageFromWaitingList(byte[] receiveMessage)
|
||||
{
|
||||
MessageWaitingDef ans;
|
||||
if (receiveMessage[0] == 0 && receiveMessage[1] == 0)
|
||||
{
|
||||
lock (WaitingMessages)
|
||||
{
|
||||
ans = WaitingMessages.FirstOrDefault();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var returnKey = GetKeyFromMessage(receiveMessage);
|
||||
lock (WaitingMessages)
|
||||
{
|
||||
ans = WaitingMessages.FirstOrDefault(p => returnKey.HasValue && p.Key == returnKey.Value.Item2);
|
||||
}
|
||||
}
|
||||
return ans;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Modbus.Net.Modbus
|
||||
namespace Modbus.Net.Modbus
|
||||
{
|
||||
/// <summary>
|
||||
/// Modbus/Rtu协议连接器Tcp透传
|
||||
@@ -24,19 +22,6 @@ namespace Modbus.Net.Modbus
|
||||
public ModbusRtuInTcpProtocolLinker(string ip, int port)
|
||||
: base(ip, port)
|
||||
{
|
||||
((IConnectorWithController<byte[], byte[]>)BaseConnector).AddController(new FifoController(
|
||||
int.Parse(ConfigurationReader.GetValue("TCP:" + ip + ":" + port, "FetchSleepTime")),
|
||||
lengthCalc: content =>
|
||||
{
|
||||
if (content[1] > 128) return 5;
|
||||
else 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);
|
||||
},
|
||||
checkRightFunc: ContentCheck.Crc16CheckRight,
|
||||
waitingListMaxCount: ConfigurationReader.GetValue("TCP:" + ip + ":" + port, "WaitingListCount") != null ?
|
||||
int.Parse(ConfigurationReader.GetValue("TCP:" + ip + ":" + port, "WaitingListCount")) :
|
||||
null
|
||||
));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Modbus.Net.Modbus
|
||||
namespace Modbus.Net.Modbus
|
||||
{
|
||||
/// <summary>
|
||||
/// Modbus/Rtu协议连接器Udp透传
|
||||
@@ -24,19 +22,6 @@ namespace Modbus.Net.Modbus
|
||||
public ModbusRtuInUdpProtocolLinker(string ip, int port)
|
||||
: base(ip, port)
|
||||
{
|
||||
((IConnectorWithController<byte[], byte[]>)BaseConnector).AddController(new FifoController(
|
||||
int.Parse(ConfigurationReader.GetValue("UDP:" + ip + ":" + port, "FetchSleepTime")),
|
||||
lengthCalc: content =>
|
||||
{
|
||||
if (content[1] > 128) return 5;
|
||||
else 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);
|
||||
},
|
||||
checkRightFunc: ContentCheck.Crc16CheckRight,
|
||||
waitingListMaxCount: ConfigurationReader.GetValue("UDP:" + ip + ":" + port, "WaitingListCount") != null ?
|
||||
int.Parse(ConfigurationReader.GetValue("UDP:" + ip + ":" + port, "WaitingListCount")) :
|
||||
null
|
||||
));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Modbus.Net.Modbus
|
||||
namespace Modbus.Net.Modbus
|
||||
{
|
||||
/// <summary>
|
||||
/// Modbus/Rtu协议连接器
|
||||
@@ -15,21 +13,6 @@ namespace Modbus.Net.Modbus
|
||||
public ModbusRtuProtocolLinker(string com, int slaveAddress)
|
||||
: base(com, slaveAddress)
|
||||
{
|
||||
((IConnectorWithController<byte[], byte[]>)BaseConnector).AddController(new FifoController(
|
||||
int.Parse(ConfigurationReader.GetValue("COM:" + com + ":" + slaveAddress, "FetchSleepTime")),
|
||||
lengthCalc: content =>
|
||||
{
|
||||
if (content[1] > 128) return 5;
|
||||
else if (content[1] == 5 || content[1] == 6 || content[1] == 8 || content[1] == 11 || content[1] == 15 || content[1] == 16) return 8;
|
||||
else if (content[1] == 7) return 5;
|
||||
else if (content[1] == 22) return 10;
|
||||
else return DuplicateWithCount.GetDuplcateFunc(new List<int> { 2 }, 5).Invoke(content);
|
||||
},
|
||||
checkRightFunc: ContentCheck.Crc16CheckRight,
|
||||
waitingListMaxCount: ConfigurationReader.GetValue("COM:" + com + ":" + slaveAddress, "WaitingListCount") != null ?
|
||||
int.Parse(ConfigurationReader.GetValue("COM:" + com + ":" + slaveAddress, "WaitingListCount")) :
|
||||
null
|
||||
));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -1,41 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Modbus.Net
|
||||
{
|
||||
/// <summary>
|
||||
/// 匹配控制器,载入队列后直接发送
|
||||
/// </summary>
|
||||
public class ModbusTcpMatchDirectlySendController : MatchDirectlySendController
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public ModbusTcpMatchDirectlySendController(ICollection<(int, int)>[] keyMatches,
|
||||
Func<byte[], int> lengthCalc = null, Func<byte[], bool?> checkRightFunc = null, int? waitingListMaxCount = null) : base(keyMatches,
|
||||
lengthCalc, checkRightFunc, waitingListMaxCount)
|
||||
{
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override MessageWaitingDef GetMessageFromWaitingList(byte[] receiveMessage)
|
||||
{
|
||||
MessageWaitingDef ans;
|
||||
if (receiveMessage[0] == 0 && receiveMessage[1] == 0)
|
||||
{
|
||||
lock (WaitingMessages)
|
||||
{
|
||||
ans = WaitingMessages.FirstOrDefault();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var returnKey = GetKeyFromMessage(receiveMessage);
|
||||
lock (WaitingMessages)
|
||||
{
|
||||
ans = WaitingMessages.FirstOrDefault(p => returnKey.HasValue && p.Key == returnKey.Value.Item2);
|
||||
}
|
||||
}
|
||||
return ans;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,4 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Modbus.Net.Modbus
|
||||
namespace Modbus.Net.Modbus
|
||||
{
|
||||
/// <summary>
|
||||
/// Modbus/Tcp协议连接器
|
||||
@@ -23,13 +21,6 @@ namespace Modbus.Net.Modbus
|
||||
/// <param name="port">端口</param>
|
||||
public ModbusTcpProtocolLinker(string ip, int port) : base(ip, port)
|
||||
{
|
||||
((IConnectorWithController<byte[], byte[]>)BaseConnector).AddController(new ModbusTcpMatchDirectlySendController(
|
||||
new ICollection<(int, int)>[] { new List<(int, int)> { (0, 0), (1, 1) } },
|
||||
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>
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Modbus.Net.Modbus
|
||||
namespace Modbus.Net.Modbus
|
||||
{
|
||||
/// <summary>
|
||||
/// Modbus/Udp协议连接器
|
||||
@@ -23,13 +21,6 @@ namespace Modbus.Net.Modbus
|
||||
/// <param name="port">端口</param>
|
||||
public ModbusUdpProtocolLinker(string ip, int port) : base(ip, port)
|
||||
{
|
||||
((IConnectorWithController<byte[], byte[]>)BaseConnector).AddController(new ModbusTcpMatchDirectlySendController(
|
||||
new ICollection<(int, int)>[] { new List<(int, int)> { (0, 0), (1, 1) } },
|
||||
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>
|
||||
|
||||
53
Modbus.Net/Modbus.Net.Siemens/SiemensController.cs
Normal file
53
Modbus.Net/Modbus.Net.Siemens/SiemensController.cs
Normal file
@@ -0,0 +1,53 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Modbus.Net.Siemens
|
||||
{
|
||||
/// <summary>
|
||||
/// 西门子Ppi协议控制器
|
||||
/// </summary>
|
||||
public class SiemensPpiController : FifoController
|
||||
{
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
/// <param name="com">串口</param>
|
||||
/// <param name="slaveAddress">从站号</param>
|
||||
public SiemensPpiController(string com, int slaveAddress) : base(
|
||||
int.Parse(ConfigurationReader.GetValue("COM:" + com + ":" + slaveAddress, "FetchSleepTime")),
|
||||
lengthCalc: content =>
|
||||
{
|
||||
if (content[0] == 0x10)
|
||||
return 6;
|
||||
else if (content[0] == 0xE5)
|
||||
return 1;
|
||||
else
|
||||
return DuplicateWithCount.GetDuplcateFunc(new List<int> { 1 }, 6)(content);
|
||||
},
|
||||
checkRightFunc: ContentCheck.FcsCheckRight,
|
||||
waitingListMaxCount: ConfigurationReader.GetValue("COM:" + com + ":" + slaveAddress, "WaitingListCount") != null ?
|
||||
int.Parse(ConfigurationReader.GetValue("COM:" + com + ":" + slaveAddress, "WaitingListCount")) :
|
||||
null
|
||||
)
|
||||
{ }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 西门子Tcp协议控制器
|
||||
/// </summary>
|
||||
public class SiemensTcpController : MatchDirectlySendController
|
||||
{
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
/// <param name="ip">ip地址</param>
|
||||
/// <param name="port">端口号</param>
|
||||
public SiemensTcpController(string ip, int port) : base(
|
||||
new ICollection<(int, int)>[] { new List<(int, int)> { (11, 11), (12, 12) } },
|
||||
lengthCalc: DuplicateWithCount.GetDuplcateFunc(new List<int> { 2, 3 }, 0),
|
||||
waitingListMaxCount: ConfigurationReader.GetValue("TCP:" + ip + ":" + port, "WaitingListCount") != null ?
|
||||
int.Parse(ConfigurationReader.GetValue("TCP:" + ip + ":" + port, "WaitingListCount")) :
|
||||
null
|
||||
)
|
||||
{ }
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO.Ports;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
@@ -23,22 +22,6 @@ namespace Modbus.Net.Siemens
|
||||
: null
|
||||
)
|
||||
{
|
||||
((IConnectorWithController<byte[], byte[]>)BaseConnector).AddController(new FifoController(
|
||||
int.Parse(ConfigurationReader.GetValue("COM:" + com + ":" + slaveAddress, "FetchSleepTime")),
|
||||
lengthCalc: content =>
|
||||
{
|
||||
if (content[0] == 0x10)
|
||||
return 6;
|
||||
else if (content[0] == 0xE5)
|
||||
return 1;
|
||||
else
|
||||
return DuplicateWithCount.GetDuplcateFunc(new List<int> { 1 }, 6)(content);
|
||||
},
|
||||
checkRightFunc: ContentCheck.FcsCheckRight,
|
||||
waitingListMaxCount: ConfigurationReader.GetValue("COM:" + com + ":" + slaveAddress, "WaitingListCount") != null ?
|
||||
int.Parse(ConfigurationReader.GetValue("COM:" + com + ":" + slaveAddress, "WaitingListCount")) :
|
||||
null
|
||||
));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Modbus.Net.Siemens
|
||||
{
|
||||
@@ -25,13 +24,6 @@ namespace Modbus.Net.Siemens
|
||||
public SiemensTcpProtocolLinker(string ip, int port)
|
||||
: base(ip, port)
|
||||
{
|
||||
((IConnectorWithController<byte[], byte[]>)BaseConnector).AddController(new MatchDirectlySendController(
|
||||
new ICollection<(int, int)>[] { new List<(int, int)> { (11, 11), (12, 12) } },
|
||||
lengthCalc: DuplicateWithCount.GetDuplcateFunc(new List<int> { 2, 3 }, 0),
|
||||
waitingListMaxCount: ConfigurationReader.GetValue("TCP:" + ip + ":" + port, "WaitingListCount") != null ?
|
||||
int.Parse(ConfigurationReader.GetValue("TCP:" + ip + ":" + port, "WaitingListCount")) :
|
||||
null
|
||||
));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -45,7 +45,11 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Technosoftware.DaAeHdaClien
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Technosoftware.DaAeHdaClient.Com", "..\Technosoftware\DaAeHdaClient.Com\Technosoftware.DaAeHdaClient.Com.csproj", "{ACAF0A16-FC51-4369-BFA8-484FF20707D7}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Modbus.Net.HJ212", "Modbus.Net.HJ212\Modbus.Net.HJ212.csproj", "{057644EF-1407-4C2B-808A-AEF0F2979EA8}"
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Modbus.Net.HJ212", "Modbus.Net.HJ212\Modbus.Net.HJ212.csproj", "{057644EF-1407-4C2B-808A-AEF0F2979EA8}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Modbus.Net.CodeGenerator", "Modbus.Net.CodeGenerator\Modbus.Net.CodeGenerator.csproj", "{D3210531-BA79-49B2-9F99-09FD0E1627B6}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MachineJob.CodeGenerator", "..\Samples\MachineJob.CodeGenerator\MachineJob.CodeGenerator.csproj", "{7337BC9A-ED07-463D-8FCD-A82896CEC6BE}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
@@ -191,6 +195,22 @@ Global
|
||||
{057644EF-1407-4C2B-808A-AEF0F2979EA8}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{057644EF-1407-4C2B-808A-AEF0F2979EA8}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{057644EF-1407-4C2B-808A-AEF0F2979EA8}.Release|x64.Build.0 = Release|Any CPU
|
||||
{D3210531-BA79-49B2-9F99-09FD0E1627B6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{D3210531-BA79-49B2-9F99-09FD0E1627B6}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{D3210531-BA79-49B2-9F99-09FD0E1627B6}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{D3210531-BA79-49B2-9F99-09FD0E1627B6}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{D3210531-BA79-49B2-9F99-09FD0E1627B6}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{D3210531-BA79-49B2-9F99-09FD0E1627B6}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{D3210531-BA79-49B2-9F99-09FD0E1627B6}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{D3210531-BA79-49B2-9F99-09FD0E1627B6}.Release|x64.Build.0 = Release|Any CPU
|
||||
{7337BC9A-ED07-463D-8FCD-A82896CEC6BE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{7337BC9A-ED07-463D-8FCD-A82896CEC6BE}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{7337BC9A-ED07-463D-8FCD-A82896CEC6BE}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{7337BC9A-ED07-463D-8FCD-A82896CEC6BE}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{7337BC9A-ED07-463D-8FCD-A82896CEC6BE}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{7337BC9A-ED07-463D-8FCD-A82896CEC6BE}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{7337BC9A-ED07-463D-8FCD-A82896CEC6BE}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{7337BC9A-ED07-463D-8FCD-A82896CEC6BE}.Release|x64.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
@@ -201,6 +221,7 @@ Global
|
||||
{1857DA63-3335-428F-84D8-1FA4F8178643} = {3597B5C5-45B9-4ECB-92A3-D0FFBE47920A}
|
||||
{AA3A42D2-0502-41D3-929A-BAB729DF07D6} = {3597B5C5-45B9-4ECB-92A3-D0FFBE47920A}
|
||||
{414956B8-DBD4-414C-ABD3-565580739646} = {3597B5C5-45B9-4ECB-92A3-D0FFBE47920A}
|
||||
{7337BC9A-ED07-463D-8FCD-A82896CEC6BE} = {3597B5C5-45B9-4ECB-92A3-D0FFBE47920A}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {AF00D64E-3C70-474A-8A81-E9E48017C4B5}
|
||||
|
||||
@@ -1,102 +1,12 @@
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Nito.AsyncEx;
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Modbus.Net
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public abstract class BaseConnector : BaseConnector<byte[], byte[]>
|
||||
public abstract partial class BaseConnector : BaseConnector<byte[], byte[]>
|
||||
{
|
||||
private static readonly ILogger<BaseConnector> logger = LogProvider.CreateLogger<BaseConnector>();
|
||||
|
||||
/// <summary>
|
||||
/// 发送锁
|
||||
/// </summary>
|
||||
protected abstract AsyncLock Lock { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否为全双工
|
||||
/// </summary>
|
||||
public bool IsFullDuplex { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 发送超时时间
|
||||
/// </summary>
|
||||
protected abstract int TimeoutTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 构造器
|
||||
/// </summary>
|
||||
/// <param name="timeoutTime">发送超时时间</param>
|
||||
/// <param name="isFullDuplex">是否为全双工</param>
|
||||
protected BaseConnector(int timeoutTime = 10000, bool isFullDuplex = false)
|
||||
{
|
||||
IsFullDuplex = isFullDuplex;
|
||||
if (timeoutTime < -1) timeoutTime = -1;
|
||||
TimeoutTime = timeoutTime;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override async Task<byte[]> SendMsgAsync(byte[] message)
|
||||
{
|
||||
var ans = await SendMsgInner(message);
|
||||
if (ans == null) return new byte[0];
|
||||
return ans.ReceiveMessage;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 发送内部
|
||||
/// </summary>
|
||||
/// <param name="message">发送的信息</param>
|
||||
/// <param name="repeat">是否为重发消息</param>
|
||||
/// <returns>发送信息的定义</returns>
|
||||
protected async Task<MessageWaitingDef> SendMsgInner(byte[] message, bool repeat = false)
|
||||
{
|
||||
IDisposable asyncLock = null;
|
||||
try
|
||||
{
|
||||
if (!Controller.IsSending)
|
||||
{
|
||||
Controller.SendStart();
|
||||
}
|
||||
var messageSendingdef = Controller.AddMessage(message);
|
||||
if (messageSendingdef != null)
|
||||
{
|
||||
if (!IsFullDuplex)
|
||||
{
|
||||
asyncLock = await Lock.LockAsync();
|
||||
}
|
||||
var success = messageSendingdef.SendMutex.WaitOne(TimeoutTime);
|
||||
if (success)
|
||||
{
|
||||
await SendMsgWithoutConfirm(message);
|
||||
success = messageSendingdef.ReceiveMutex.WaitOne(TimeoutTime);
|
||||
if (success)
|
||||
{
|
||||
if (!repeat && messageSendingdef.ReceiveMessage == null)
|
||||
{
|
||||
asyncLock?.Dispose();
|
||||
return await SendMsgInner(message, true);
|
||||
}
|
||||
return messageSendingdef;
|
||||
}
|
||||
}
|
||||
Controller.ForceRemoveWaitingMessage(messageSendingdef);
|
||||
}
|
||||
logger.LogInformation("Message is waiting in {0}. Cancel!", ConnectionToken);
|
||||
return null;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
logger.LogError(e, "Connector {0} Send Error.", ConnectionToken);
|
||||
return null;
|
||||
}
|
||||
finally
|
||||
{
|
||||
asyncLock?.Dispose();
|
||||
}
|
||||
}
|
||||
private static readonly ILogger<EventHandlerConnector> logger = LogProvider.CreateLogger<EventHandlerConnector>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -1,106 +1,17 @@
|
||||
using DotNetty.Transport.Channels;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Nito.AsyncEx;
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Modbus.Net
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public abstract class EventHandlerConnector : EventHandlerConnector<byte[], byte[]>
|
||||
public abstract partial class EventHandlerConnector : EventHandlerConnector<byte[], byte[]>
|
||||
{
|
||||
/// <inheridoc />
|
||||
public override bool IsSharable => true;
|
||||
|
||||
private static readonly ILogger<EventHandlerConnector> logger = LogProvider.CreateLogger<EventHandlerConnector>();
|
||||
|
||||
/// <summary>
|
||||
/// 发送锁
|
||||
/// </summary>
|
||||
protected abstract AsyncLock Lock { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否为全双工
|
||||
/// </summary>
|
||||
public bool IsFullDuplex { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 发送超时时间
|
||||
/// </summary>
|
||||
protected abstract int TimeoutTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 构造器
|
||||
/// </summary>
|
||||
/// <param name="timeoutTime">发送超时时间</param>
|
||||
/// <param name="isFullDuplex">是否为全双工</param>
|
||||
protected EventHandlerConnector(int timeoutTime = 10000, bool isFullDuplex = true)
|
||||
{
|
||||
IsFullDuplex = isFullDuplex;
|
||||
if (timeoutTime < -1) timeoutTime = -1;
|
||||
TimeoutTime = timeoutTime;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override async Task<byte[]> SendMsgAsync(byte[] message)
|
||||
{
|
||||
var ans = await SendMsgInner(message);
|
||||
if (ans == null) return new byte[0];
|
||||
return ans.ReceiveMessage;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 发送内部
|
||||
/// </summary>
|
||||
/// <param name="message">发送的信息</param>
|
||||
/// <param name="repeat">是否为重发消息</param>
|
||||
/// <returns>发送信息的定义</returns>
|
||||
protected async Task<MessageWaitingDef> SendMsgInner(byte[] message, bool repeat = false)
|
||||
{
|
||||
IDisposable asyncLock = null;
|
||||
try
|
||||
{
|
||||
if (!Controller.IsSending)
|
||||
{
|
||||
Controller.SendStart();
|
||||
}
|
||||
var messageSendingdef = Controller.AddMessage(message);
|
||||
if (messageSendingdef != null)
|
||||
{
|
||||
if (!IsFullDuplex)
|
||||
{
|
||||
asyncLock = await Lock.LockAsync();
|
||||
}
|
||||
var success = messageSendingdef.SendMutex.WaitOne(TimeoutTime);
|
||||
if (success)
|
||||
{
|
||||
await SendMsgWithoutConfirm(message);
|
||||
success = messageSendingdef.ReceiveMutex.WaitOne(TimeoutTime);
|
||||
if (success)
|
||||
{
|
||||
if (!repeat && messageSendingdef.ReceiveMessage == null)
|
||||
{
|
||||
asyncLock?.Dispose();
|
||||
return await SendMsgInner(message, true);
|
||||
}
|
||||
return messageSendingdef;
|
||||
}
|
||||
}
|
||||
Controller.ForceRemoveWaitingMessage(messageSendingdef);
|
||||
}
|
||||
logger.LogInformation("Message is waiting in {0}. Cancel!", ConnectionToken);
|
||||
return null;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
logger.LogError(e, "Connector {0} Send Error.", ConnectionToken);
|
||||
return null;
|
||||
}
|
||||
finally
|
||||
{
|
||||
asyncLock?.Dispose();
|
||||
}
|
||||
}
|
||||
/// <inheridoc />
|
||||
public override bool IsSharable => true;
|
||||
|
||||
/// <inheridoc />
|
||||
public override void ChannelReadComplete(IChannelHandlerContext ctx)
|
||||
|
||||
41
Modbus.Net/Modbus.Net/Helper/ControllerHelper.cs
Normal file
41
Modbus.Net/Modbus.Net/Helper/ControllerHelper.cs
Normal file
@@ -0,0 +1,41 @@
|
||||
using System;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Modbus.Net
|
||||
{
|
||||
/// <summary>
|
||||
/// ProtocolLinker添加Controller扩展方法
|
||||
/// </summary>
|
||||
public static class ControllerHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// 添加一个Controller
|
||||
/// </summary>
|
||||
/// <param name="protocolLinker">ProtocolLinker实例</param>
|
||||
/// <param name="param1">第一参数</param>
|
||||
/// <param name="param2">第二参数</param>
|
||||
/// <param name="connector">Connector实例</param>
|
||||
/// <exception cref="NotImplementedException">如果没有发现控制器,报错</exception>
|
||||
public static void AddController(this IProtocolLinker<byte[], byte[]> protocolLinker, string param1, int param2, IConnector<byte[], byte[]> connector)
|
||||
{
|
||||
IController controller = null;
|
||||
var assemblies = AssemblyHelper.GetAllLibraryAssemblies();
|
||||
string controllerName = protocolLinker.GetType().Name.Substring(0, protocolLinker.GetType().Name.Length - 14) + "Controller";
|
||||
foreach (var assembly in assemblies)
|
||||
{
|
||||
var controllerType = assembly.GetType(assembly.GetName().Name + "." + controllerName);
|
||||
if (controllerType != null)
|
||||
{
|
||||
controller = assembly.CreateInstance(controllerType.FullName, true, BindingFlags.Default, null, new object[2] { param1, param2 }, null, null) as IController;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (controller != null)
|
||||
{
|
||||
((IConnectorWithController<byte[], byte[]>)connector).AddController(controller);
|
||||
return;
|
||||
}
|
||||
throw new NotImplementedException(controllerName + " not found exception");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -31,6 +31,7 @@ namespace Modbus.Net
|
||||
connectionTimeout = int.Parse(connectionTimeout != null ? connectionTimeout.ToString() : null ?? ConfigurationReader.GetValue("COM:" + com, "ConnectionTimeout"));
|
||||
isFullDuplex = bool.Parse(isFullDuplex != null ? isFullDuplex.ToString() : null ?? ConfigurationReader.GetValue("COM:" + com, "FullDuplex"));
|
||||
BaseConnector = new ComConnector(com + ":" + slaveAddress, baudRate.Value, parity.Value, stopBits.Value, dataBits.Value, handshake.Value, connectionTimeout.Value, isFullDuplex.Value);
|
||||
this.AddController(com, slaveAddress, BaseConnector);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -18,6 +18,7 @@
|
||||
isFullDuplex = bool.Parse(isFullDuplex != null ? isFullDuplex.ToString() : null ?? ConfigurationReader.GetValue("TCP:" + ip + ":" + port, "FullDuplex"));
|
||||
//初始化连接对象
|
||||
BaseConnector = new TcpConnector(ip, port, connectionTimeout.Value, isFullDuplex.Value);
|
||||
this.AddController(ip, port, BaseConnector);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -18,6 +18,7 @@
|
||||
isFullDuplex = bool.Parse(isFullDuplex != null ? isFullDuplex.ToString() : null ?? ConfigurationReader.GetValue("UDP:" + ip + ":" + port, "FullDuplex"));
|
||||
//初始化连接对象
|
||||
BaseConnector = new UdpConnector(ip, port, connectionTimeout.Value, isFullDuplex.Value);
|
||||
this.AddController(ip, port, BaseConnector);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -34,7 +34,7 @@
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="DotNetty.Handlers" Version="0.7.5" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="7.0.4" />
|
||||
@@ -47,5 +47,11 @@
|
||||
|
||||
<ItemGroup>
|
||||
<None Include="README.md" Pack="true" PackagePath="" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Modbus.Net.CodeGenerator\Modbus.Net.CodeGenerator.csproj"
|
||||
OutputItemType="Analyzer"
|
||||
ReferenceOutputAssembly="false" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,33 @@
|
||||
using Microsoft.CodeAnalysis;
|
||||
|
||||
namespace Modbus.Net.CodeGenerator
|
||||
{
|
||||
[Generator]
|
||||
public class DatabaseWriteEntityCodeGenerator : ISourceGenerator
|
||||
{
|
||||
public void Execute(GeneratorExecutionContext context)
|
||||
{
|
||||
var content = "";
|
||||
for (int i = 1; i <= 10; i++)
|
||||
{
|
||||
content += $@"public double? Value{i} {{ get; set; }}
|
||||
";
|
||||
}
|
||||
var source = $@"
|
||||
|
||||
namespace MachineJob
|
||||
{{
|
||||
public partial class DatabaseWriteEntity
|
||||
{{
|
||||
{content}
|
||||
}}
|
||||
}}";
|
||||
context.AddSource("DatabaseWriteContent.g.cs", source);
|
||||
}
|
||||
|
||||
public void Initialize(GeneratorInitializationContext context)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Library</OutputType>
|
||||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
<LangVersion>9.0</LangVersion>
|
||||
<EnforceExtendedAnalyzerRules>true</EnforceExtendedAnalyzerRules>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.6.0" />
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
</Project>
|
||||
@@ -24,20 +24,11 @@ namespace MachineJob
|
||||
}
|
||||
|
||||
[Table(name: "databasewrites")]
|
||||
public class DatabaseWriteEntity
|
||||
public partial class DatabaseWriteEntity
|
||||
{
|
||||
[Key]
|
||||
public int Id { get; set; }
|
||||
public double? Value1 { get; set; }
|
||||
public double? Value2 { get; set; }
|
||||
public double? Value3 { get; set; }
|
||||
public double? Value4 { get; set; }
|
||||
public double? Value5 { get; set; }
|
||||
public double? Value6 { get; set; }
|
||||
public double? Value7 { get; set; }
|
||||
public double? Value8 { get; set; }
|
||||
public double? Value9 { get; set; }
|
||||
public double? Value10 { get; set; }
|
||||
|
||||
public DateTime UpdateTime { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,5 +27,8 @@
|
||||
<ProjectReference Include="..\..\Modbus.Net\Modbus.Net.OPC\Modbus.Net.Opc.csproj" />
|
||||
<ProjectReference Include="..\..\Modbus.Net\Modbus.Net.Siemens\Modbus.Net.Siemens.csproj" />
|
||||
<ProjectReference Include="..\..\Modbus.Net\Modbus.Net\Modbus.Net.csproj" />
|
||||
<ProjectReference Include="..\MachineJob.CodeGenerator\MachineJob.CodeGenerator.csproj"
|
||||
OutputItemType="Analyzer"
|
||||
ReferenceOutputAssembly="false" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
||||
Reference in New Issue
Block a user