Added implementation of Modbus TCP Server
This commit is contained in:
@@ -1,3 +1,4 @@
|
|||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
[assembly: InternalsVisibleTo("AMWD.Protocols.Modbus.Tests")]
|
[assembly: InternalsVisibleTo("AMWD.Protocols.Modbus.Tests")]
|
||||||
|
[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")]
|
||||||
|
|||||||
@@ -59,6 +59,15 @@ namespace AMWD.Protocols.Modbus.Common.Protocols
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public const ushort MAX_REGISTER_WRITE_COUNT = 0x007B; // 123
|
public const ushort MAX_REGISTER_WRITE_COUNT = 0x007B; // 123
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The maximum allowed ADU length in bytes.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// A Modbus frame consists of a PDU (protcol data unit) and additional protocol addressing / error checks.
|
||||||
|
/// The whole data frame is called ADU (application data unit).
|
||||||
|
/// </remarks>
|
||||||
|
public const int MAX_ADU_LENGTH = 260; // bytes
|
||||||
|
|
||||||
#endregion Constants
|
#endregion Constants
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
|
|||||||
@@ -13,6 +13,12 @@
|
|||||||
<PackageTags>Modbus Protocol Network TCP LAN</PackageTags>
|
<PackageTags>Modbus Protocol Network TCP LAN</PackageTags>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Compile Include="../AMWD.Protocols.Modbus.Common/InternalsVisibleTo.cs" Link="InternalsVisibleTo.cs" />
|
||||||
|
<Compile Include="../AMWD.Protocols.Modbus.Common/Extensions/ArrayExtensions.cs" Link="Extensions/ArrayExtensions.cs" />
|
||||||
|
<Compile Include="../AMWD.Protocols.Modbus.Common/Extensions/ReaderWriterLockSlimExtensions.cs" Link="Extensions/ReaderWriterLockSlimExtensions.cs" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Include="README.md" Pack="true" PackagePath="/" />
|
<None Include="README.md" Pack="true" PackagePath="/" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|||||||
25
AMWD.Protocols.Modbus.Tcp/Events/CoilWrittenEventArgs.cs
Normal file
25
AMWD.Protocols.Modbus.Tcp/Events/CoilWrittenEventArgs.cs
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace AMWD.Protocols.Modbus.Tcp.Events
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents the coil written event arguments.
|
||||||
|
/// </summary>
|
||||||
|
public class CoilWrittenEventArgs : EventArgs
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the unit id.
|
||||||
|
/// </summary>
|
||||||
|
public byte UnitId { get; internal set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the coil address.
|
||||||
|
/// </summary>
|
||||||
|
public ushort Address { get; internal set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the coil value.
|
||||||
|
/// </summary>
|
||||||
|
public bool Value { get; internal set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
35
AMWD.Protocols.Modbus.Tcp/Events/RegisterWrittenEventArgs.cs
Normal file
35
AMWD.Protocols.Modbus.Tcp/Events/RegisterWrittenEventArgs.cs
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace AMWD.Protocols.Modbus.Tcp.Events
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents the register written event arguments.
|
||||||
|
/// </summary>
|
||||||
|
public class RegisterWrittenEventArgs : EventArgs
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the unit id.
|
||||||
|
/// </summary>
|
||||||
|
public byte UnitId { get; internal set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the address of the register.
|
||||||
|
/// </summary>
|
||||||
|
public ushort Address { get; internal set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the value of the register.
|
||||||
|
/// </summary>
|
||||||
|
public ushort Value { get; internal set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the high byte of the register.
|
||||||
|
/// </summary>
|
||||||
|
public byte HighByte { get; internal set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the low byte of the register.
|
||||||
|
/// </summary>
|
||||||
|
public byte LowByte { get; internal set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
26
AMWD.Protocols.Modbus.Tcp/Extensions/StreamExtensions.cs
Normal file
26
AMWD.Protocols.Modbus.Tcp/Extensions/StreamExtensions.cs
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace System.IO
|
||||||
|
{
|
||||||
|
internal static class StreamExtensions
|
||||||
|
{
|
||||||
|
public static async Task<byte[]> ReadExpectedBytesAsync(this Stream stream, int expectedBytes, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
byte[] buffer = new byte[expectedBytes];
|
||||||
|
int offset = 0;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
int count = await stream.ReadAsync(buffer, offset, expectedBytes - offset, cancellationToken).ConfigureAwait(false);
|
||||||
|
if (count < 1)
|
||||||
|
throw new EndOfStreamException();
|
||||||
|
|
||||||
|
offset += count;
|
||||||
|
}
|
||||||
|
while (offset < expectedBytes && !cancellationToken.IsCancellationRequested);
|
||||||
|
|
||||||
|
cancellationToken.ThrowIfCancellationRequested();
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
using System.Runtime.CompilerServices;
|
|
||||||
|
|
||||||
[assembly: InternalsVisibleTo("AMWD.Protocols.Modbus.Tests")]
|
|
||||||
[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")]
|
|
||||||
1149
AMWD.Protocols.Modbus.Tcp/ModbusTcpServer.cs
Normal file
1149
AMWD.Protocols.Modbus.Tcp/ModbusTcpServer.cs
Normal file
File diff suppressed because it is too large
Load Diff
@@ -161,8 +161,8 @@ namespace AMWD.Protocols.Modbus.Tests.Tcp.Utils
|
|||||||
public async Task ShouldThrowApplicationExceptionHostnameNotResolvable()
|
public async Task ShouldThrowApplicationExceptionHostnameNotResolvable()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
_hostname = "123.321.123.321";
|
|
||||||
var connection = GetConnection();
|
var connection = GetConnection();
|
||||||
|
connection.GetType().GetField("_hostname", BindingFlags.NonPublic | BindingFlags.Instance).SetValue(connection, "");
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
await connection.ConnectAsync();
|
await connection.ConnectAsync();
|
||||||
|
|||||||
Reference in New Issue
Block a user