├── .editorconfig
├── .github
├── dependabot.yml
└── workflows
│ ├── BuildOnly.yml
│ └── dotnet.yml
├── .gitignore
├── Directory.Build.props
├── Images
├── ModbusRx.ico
└── ModbusRx.png
├── LICENSE
├── README.md
├── Version.json
├── src
├── ModbusRx.DriverTest
│ ├── ModbusRx.DriverTest.csproj
│ └── Program.cs
├── ModbusRx.IntegrationTests
│ ├── CustomMessages
│ │ ├── CustomReadHoldingRegistersRequest.cs
│ │ ├── CustomReadHoldingRegistersResponse.cs
│ │ ├── CustomWriteMultipleRegistersRequest.cs
│ │ └── CustomWriteMultipleRegistersResponse.cs
│ ├── EnronFixture.cs
│ ├── ModbusRx.IntegrationTests.csproj
│ ├── ModbusRxIpMasterFixture.cs
│ ├── ModbusRxMasterFixture.cs
│ ├── ModbusRxSerialAsciiMasterFixture.cs
│ ├── ModbusRxSerialAsciiMasterJamodSerialAsciiSlaveFixture.cs
│ ├── ModbusRxSerialAsciiMasterModbusRxSerialAsciiSlaveFixture.cs
│ ├── ModbusRxSerialMasterFixture.cs
│ ├── ModbusRxSerialRtuMasterDl06SlaveFixture.cs
│ ├── ModbusRxSerialRtuMasterFixture.cs
│ ├── ModbusRxSerialRtuMasterModbusRxSerialRtuSlaveFixture.cs
│ ├── ModbusRxSerialRtuSlaveFixture.cs
│ ├── ModbusRxTcpMasterJamodTcpSlaveFixture.cs
│ ├── ModbusRxTcpMasterNModbusTcpSlaveFixture.cs
│ ├── ModbusRxTcpSlaveFixture.cs
│ ├── ModbusRxUdpMasterModbusRxUdpSlaveFixture.cs
│ ├── ModbusRxUdpSlaveFixture.cs
│ ├── Properties
│ │ └── AssemblyInfo.cs
│ └── TestCases.cs
├── ModbusRx.UnitTests
│ ├── Data
│ │ ├── BoolModbusDataCollectionFixture.cs
│ │ ├── DataStoreEventArgsFixture.cs
│ │ ├── DataStoreFixture.cs
│ │ ├── DiscreteCollectionFixture.cs
│ │ ├── ModbusDataCollectionFixture.cs
│ │ ├── RegisterCollectionFixture.cs
│ │ └── UshortModbusDataCollectionFixture.cs
│ ├── Device
│ │ ├── ModbusMasterFixture.cs
│ │ ├── ModbusSlaveFixture.cs
│ │ └── TcpConnectionEventArgsFixture.cs
│ ├── IO
│ │ ├── EmptyTransportFixture.cs
│ │ ├── ModbusAsciiTransportFixture.cs
│ │ ├── ModbusRtuTransportFixture.cs
│ │ ├── ModbusSerialTransportFixture.cs
│ │ ├── ModbusTcpTransportFixture.cs
│ │ ├── ModbusTransportFixture.cs
│ │ └── UdpClientAdapterFixture.cs
│ ├── InvalidModbusRequestExceptionFixture.cs
│ ├── Message
│ │ ├── DiagnosticsRequestResponseFixture.cs
│ │ ├── MessageUtility.cs
│ │ ├── ModbusMessageFactoryFixture.cs
│ │ ├── ModbusMessageFixture.cs
│ │ ├── ModbusMessageImplFixture.cs
│ │ ├── ModbusMessageWithDataFixture.cs
│ │ ├── ReadCoilsInputsRequestFixture.cs
│ │ ├── ReadCoilsInputsResponseFixture.cs
│ │ ├── ReadHoldingInputRegistersRequestFixture.cs
│ │ ├── ReadHoldingInputRegistersResponseFixture.cs
│ │ ├── ReadWriteMultipleRegistersRequestFixture.cs
│ │ ├── ReturnQueryDataRequestResponseFixture.cs
│ │ ├── SlaveExceptionResponseFixture.cs
│ │ ├── WriteMultipleCoilsRequestFixture.cs
│ │ ├── WriteMultipleCoilsResponseFixture.cs
│ │ ├── WriteMultipleRegistersRequestFixture.cs
│ │ ├── WriteMultipleRegistersResponseFixture.cs
│ │ ├── WriteSingleCoilRequestResponseFixture.cs
│ │ └── WriteSingleRegisterRequestResponseFixture.cs
│ ├── ModbusRx.UnitTests.csproj
│ ├── SlaveExceptionFixture.cs
│ └── Utility
│ │ ├── CollectionUtilityFixture.cs
│ │ ├── DiscriminatedUnionFixture.cs
│ │ └── ModbusUtilityFixture.cs
├── ModbusRx.sln
└── ModbusRx
│ ├── Data
│ ├── DataStore.cs
│ ├── DataStoreEventArgs.cs
│ ├── DataStoreFactory.cs
│ ├── DiscreteCollection.cs
│ ├── IDataCollection.cs
│ ├── ModbusDataCollection.cs
│ ├── ModbusDataType.cs
│ └── RegisterCollection.cs
│ ├── Device
│ ├── IModbusMaster.cs
│ ├── IModbusSerialMaster.cs
│ ├── ModbusDevice.cs
│ ├── ModbusIpMaster.cs
│ ├── ModbusMaster.cs
│ ├── ModbusMasterTcpConnection.cs
│ ├── ModbusSerialMaster.cs
│ ├── ModbusSerialSlave.cs
│ ├── ModbusSlave.cs
│ ├── ModbusSlaveRequestEventArgs.cs
│ ├── ModbusTcpSlave.cs
│ ├── ModbusUdpSlave.cs
│ └── TcpConnectionEventArgs.cs
│ ├── Extensions
│ └── Enron
│ │ └── EnronModbus.cs
│ ├── GlobalSuppressions.cs
│ ├── IO
│ ├── EmptyTransport.cs
│ ├── IStreamResource.cs
│ ├── ModbusAsciiTransport.cs
│ ├── ModbusIpTransport.cs
│ ├── ModbusRtuTransport.cs
│ ├── ModbusSerialTransport.cs
│ ├── ModbusTransport.cs
│ ├── SerialPortAdapter.cs
│ ├── StreamResourceUtility.cs
│ ├── TcpClientAdapter.cs
│ └── UdpClientAdapter.cs
│ ├── InvalidModbusRequestException.cs
│ ├── Message
│ ├── AbstractModbusMessage.cs
│ ├── AbstractModbusMessageWithData.cs
│ ├── DiagnosticsRequestResponse.cs
│ ├── IModbusMessage.cs
│ ├── IModbusRequest.cs
│ ├── ModbusMessageFactory.cs
│ ├── ModbusMessageImpl.cs
│ ├── ReadCoilsInputsRequest.cs
│ ├── ReadCoilsInputsResponse.cs
│ ├── ReadHoldingInputRegistersRequest.cs
│ ├── ReadHoldingInputRegistersResponse.cs
│ ├── ReadWriteMultipleRegistersRequest.cs
│ ├── SlaveExceptionResponse.cs
│ ├── WriteMultipleCoilsRequest.cs
│ ├── WriteMultipleCoilsResponse.cs
│ ├── WriteMultipleRegistersRequest.cs
│ ├── WriteMultipleRegistersResponse.cs
│ ├── WriteSingleCoilRequestResponse.cs
│ └── WriteSingleRegisterRequestResponse.cs
│ ├── Modbus.cs
│ ├── ModbusRx.csproj
│ ├── Reactive
│ ├── Create.cs
│ ├── ModbusCommunicationException.cs
│ ├── ModbusSerialSlaveExtensions.cs
│ ├── ModbusTcpSlaveExtensions.cs
│ └── ModbusUdpSlaveExtensions.cs
│ ├── Resources.cs
│ ├── SlaveException.cs
│ ├── Unme.Common
│ ├── DisposableUtility.cs
│ └── SequenceUtility.cs
│ └── Utility
│ ├── DiscriminatedUnion.cs
│ └── ModbusUtility.cs
└── stylecop.json
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | # Please see the documentation for all configuration options:
2 | # https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
3 |
4 | version: 2
5 | updates:
6 | - package-ecosystem: "nuget" # See documentation for possible values
7 | directory: "/" # Location of package manifests
8 | schedule:
9 | interval: "monthly"
10 | time: "08:00"
11 | timezone: "Europe/London"
12 | open-pull-requests-limit: 20
13 |
--------------------------------------------------------------------------------
/.github/workflows/BuildOnly.yml:
--------------------------------------------------------------------------------
1 | name: ModbusRx CI-BuildOnly
2 |
3 | on:
4 | push:
5 | branches-ignore:
6 | - main
7 |
8 | jobs:
9 | windows-latest:
10 | name: windows-latest
11 | runs-on: windows-latest
12 | steps:
13 | - name: Checkout
14 | uses: actions/checkout@v4
15 | with:
16 | fetch-depth: 0 # avoid shallow clone so nbgv can do its work.
17 |
18 | - name: Setup .NET
19 | uses: actions/setup-dotnet@v4
20 | with:
21 | dotnet-version: |
22 | 6.0.x
23 | 7.0.x
24 | 8.0.x
25 |
26 | - name: Add MSBuild to PATH
27 | uses: glennawatson/setup-msbuild@v1.0.3
28 | with:
29 | prerelease: true
30 |
31 | - name: NBGV
32 | id: nbgv
33 | uses: dotnet/nbgv@master
34 | with:
35 | setAllVars: true
36 | - run: echo 'SemVer2=${{ steps.nbgv.outputs.SemVer2 }}'
37 |
38 | - name: NuGet Restore
39 | run: dotnet restore ModbusRx.sln
40 | working-directory: src
41 |
42 | - name: Build
43 | run: msbuild /t:build,pack /nowarn:MSB4011 /maxcpucount /p:NoPackageAnalysis=true /verbosity:minimal /p:Configuration=Release ModbusRx.sln
44 | working-directory: src
45 |
46 | - name: Run Unit Tests and Generate Coverage
47 | uses: glennawatson/coverlet-msbuild@v2
48 | with:
49 | project-files: 'src/**/*Tests*.csproj'
50 | no-build: true
51 | include-filter: 'ModbusRx*'
52 | output-format: cobertura
53 | configuration: Release
54 |
55 | - name: Upload Code Coverage
56 | uses: codecov/codecov-action@v5
57 |
58 | - name: Create NuGet Artifacts
59 | uses: actions/upload-artifact@master
60 | with:
61 | name: nuget
62 | path: '**/*.nupkg'
63 |
--------------------------------------------------------------------------------
/.github/workflows/dotnet.yml:
--------------------------------------------------------------------------------
1 | name: ModbusRx CI-Build
2 |
3 | on:
4 | push:
5 | branches:
6 | - main
7 |
8 | jobs:
9 | windows-latest:
10 | name: windows-latest
11 | runs-on: windows-latest
12 |
13 | permissions: write-all
14 | environment:
15 | name: release
16 | steps:
17 | - name: Checkout
18 | uses: actions/checkout@v4
19 | with:
20 | fetch-depth: 0 # avoid shallow clone so nbgv can do its work.
21 |
22 | - name: Setup .NET
23 | uses: actions/setup-dotnet@v4
24 | with:
25 | dotnet-version: |
26 | 6.0.x
27 | 7.0.x
28 | 8.0.x
29 |
30 | - name: Add MSBuild to PATH
31 | uses: glennawatson/setup-msbuild@v1.0.3
32 | with:
33 | prerelease: true
34 |
35 | - name: NBGV
36 | id: nbgv
37 | uses: dotnet/nbgv@master
38 | with:
39 | setAllVars: true
40 | - run: echo 'SemVer2=${{ steps.nbgv.outputs.SemVer2 }}'
41 |
42 | - name: NuGet Restore
43 | run: dotnet restore ModbusRx.sln
44 | working-directory: src
45 |
46 | - name: Build
47 | run: msbuild /t:build,pack /nowarn:MSB4011 /maxcpucount /p:NoPackageAnalysis=true /verbosity:minimal /p:Configuration=Release ModbusRx.sln
48 | working-directory: src
49 |
50 | - name: Run Unit Tests and Generate Coverage
51 | uses: glennawatson/coverlet-msbuild@v2
52 | with:
53 | project-files: 'src/**/*Tests*.csproj'
54 | no-build: true
55 | include-filter: 'ModbusRx*'
56 | output-format: cobertura
57 | configuration: Release
58 |
59 | - name: Upload Code Coverage
60 | uses: codecov/codecov-action@v5
61 |
62 | - name: Create NuGet Artifacts
63 | uses: actions/upload-artifact@master
64 | with:
65 | name: nuget
66 | path: '**/*.nupkg'
67 |
68 | - name: NuGet Push
69 | env:
70 | NUGET_AUTH_TOKEN: ${{ secrets.NUGET_API_KEY }}
71 | SOURCE_URL: https://api.nuget.org/v3/index.json
72 | run: |
73 | dotnet nuget push -s ${{ env.SOURCE_URL }} -k ${{ env.NUGET_AUTH_TOKEN }} **/*.nupkg --skip-duplicate
74 |
75 | - name: Changelog
76 | uses: glennawatson/ChangeLog@v1
77 | id: changelog
78 |
79 | - name: Create Release
80 | uses: actions/create-release@v1.1.4
81 | env:
82 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # This token is provided by Actions, you do not need to create your own token
83 | with:
84 | tag_name: ${{ steps.nbgv.outputs.SemVer2 }}
85 | release_name: ${{ steps.nbgv.outputs.SemVer2 }}
86 | body: |
87 | ${{ steps.changelog.outputs.commitLog }}
88 |
--------------------------------------------------------------------------------
/Images/ModbusRx.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ChrisPulman/ModbusRx/1ce1e87c2d6fe12350fd0f1ef0f8112bece09487/Images/ModbusRx.ico
--------------------------------------------------------------------------------
/Images/ModbusRx.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ChrisPulman/ModbusRx/1ce1e87c2d6fe12350fd0f1ef0f8112bece09487/Images/ModbusRx.png
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2022 Chris Pulman
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ChrisPulman/ModbusRx/1ce1e87c2d6fe12350fd0f1ef0f8112bece09487/README.md
--------------------------------------------------------------------------------
/Version.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://raw.githubusercontent.com/dotnet/Nerdbank.GitVersioning/main/src/NerdBank.GitVersioning/version.schema.json",
3 | "version": "1.0",
4 | "publicReleaseRefSpec": [
5 | "^refs/heads/master$",
6 | "^refs/heads/main$"
7 | ],
8 | "nugetPackageVersion": {
9 | "semVer": 2,
10 | "precision": "build"
11 | },
12 | "cloudBuild": {
13 | "setVersionVariables": true,
14 | "buildNumber": {
15 | "enabled": false
16 | }
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/ModbusRx.DriverTest/ModbusRx.DriverTest.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Exe
5 | net6.0
6 | enable
7 | enable
8 | false
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/src/ModbusRx.DriverTest/Program.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Chris Pulman. All rights reserved.
2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3 |
4 | using System.Reactive.Linq;
5 | using ModbusRx.Reactive;
6 |
7 | namespace ModbusRx.DriverTest
8 | {
9 | internal static class Program
10 | {
11 | private static void Main(string[] args)
12 | {
13 | try
14 | {
15 | Create.TcpIpSlave("127.0.0.1")
16 | .WriteHoldingRegisters(0, Observable.Return(new ushort[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 }))
17 | .Subscribe(slave =>
18 | {
19 | Console.WriteLine(slave.Masters.Count);
20 | });
21 |
22 | Create.TcpIpMaster("127.0.0.1")
23 | .Where(x => x.master != null)
24 | .Do(async x => await x.master!.WriteMultipleRegistersAsync(0, new ushort[] { 100, 101 }))
25 | .ReadHoldingRegisters(0, 12)
26 | .Subscribe(modbus =>
27 | {
28 | for (var i = 0; i < modbus.data?.Length; i++)
29 | {
30 | Console.WriteLine($"Input {i}={modbus.data[i]}");
31 | }
32 | });
33 |
34 | Console.ReadLine();
35 | }
36 | catch (Exception e)
37 | {
38 | Console.WriteLine(e.Message);
39 | }
40 | }
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/src/ModbusRx.IntegrationTests/CustomMessages/CustomReadHoldingRegistersResponse.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Chris Pulman. All rights reserved.
2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3 |
4 | using System;
5 | using System.Collections.Generic;
6 | using System.Linq;
7 | using ModbusRx.Data;
8 | using ModbusRx.Message;
9 |
10 | namespace ModbusRx.IntegrationTests.CustomMessages;
11 |
12 | ///
13 | /// CustomReadHoldingRegistersResponse.
14 | ///
15 | ///
16 | public class CustomReadHoldingRegistersResponse : IModbusMessage
17 | {
18 | ///
19 | /// The data.
20 | ///
21 | private RegisterCollection? _data;
22 |
23 | ///
24 | /// Gets the data.
25 | ///
26 | ///
27 | /// The data.
28 | ///
29 | public ushort[] Data => _data!.ToArray();
30 |
31 | ///
32 | /// Gets composition of the slave address and protocol data unit.
33 | ///
34 | public byte[] MessageFrame
35 | {
36 | get
37 | {
38 | var frame = new List()
39 | {
40 | SlaveAddress
41 | };
42 | frame.AddRange(ProtocolDataUnit);
43 |
44 | return frame.ToArray();
45 | }
46 | }
47 |
48 | ///
49 | /// Gets composition of the function code and message data.
50 | ///
51 | public byte[] ProtocolDataUnit
52 | {
53 | get
54 | {
55 | var pdu = new List
56 | {
57 | FunctionCode,
58 | ByteCount
59 | };
60 | pdu.AddRange(_data!.NetworkBytes);
61 |
62 | return pdu.ToArray();
63 | }
64 | }
65 |
66 | ///
67 | /// Gets or sets a unique identifier assigned to a message when using the IP protocol.
68 | ///
69 | public ushort TransactionId { get; set; }
70 |
71 | ///
72 | /// Gets or sets the function code tells the server what kind of action to perform.
73 | ///
74 | public byte FunctionCode { get; set; }
75 |
76 | ///
77 | /// Gets or sets address of the slave (server).
78 | ///
79 | public byte SlaveAddress { get; set; }
80 |
81 | ///
82 | /// Gets or sets the byte count.
83 | ///
84 | ///
85 | /// The byte count.
86 | ///
87 | public byte ByteCount { get; set; }
88 |
89 | ///
90 | /// Initializes a modbus message from the specified message frame.
91 | ///
92 | /// Bytes of Modbus frame.
93 | /// frame.
94 | /// Message frame does not contain enough bytes. - frame.
95 | public void Initialize(byte[] frame)
96 | {
97 | if (frame == null)
98 | {
99 | throw new ArgumentNullException(nameof(frame));
100 | }
101 |
102 | if (frame.Length < 3 || frame.Length < 3 + frame[2])
103 | {
104 | throw new ArgumentException("Message frame does not contain enough bytes.", nameof(frame));
105 | }
106 |
107 | SlaveAddress = frame[0];
108 | FunctionCode = frame[1];
109 | ByteCount = frame[2];
110 | _data = new RegisterCollection(frame.Skip(3).Take(ByteCount).ToArray());
111 | }
112 | }
113 |
--------------------------------------------------------------------------------
/src/ModbusRx.IntegrationTests/CustomMessages/CustomWriteMultipleRegistersResponse.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Chris Pulman. All rights reserved.
2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3 |
4 | using System;
5 | using System.Collections.Generic;
6 | using System.Net;
7 | using ModbusRx.Message;
8 |
9 | namespace ModbusRx.IntegrationTests.CustomMessages;
10 |
11 | ///
12 | /// CustomWriteMultipleRegistersResponse.
13 | ///
14 | ///
15 | public class CustomWriteMultipleRegistersResponse : IModbusMessage
16 | {
17 | ///
18 | /// Gets composition of the slave address and protocol data unit.
19 | ///
20 | public byte[] MessageFrame
21 | {
22 | get
23 | {
24 | var frame = new List
25 | {
26 | SlaveAddress
27 | };
28 | frame.AddRange(ProtocolDataUnit);
29 |
30 | return frame.ToArray();
31 | }
32 | }
33 |
34 | ///
35 | /// Gets composition of the function code and message data.
36 | ///
37 | public byte[] ProtocolDataUnit
38 | {
39 | get
40 | {
41 | var pdu = new List
42 | {
43 | FunctionCode
44 | };
45 | pdu.AddRange(BitConverter.GetBytes(IPAddress.HostToNetworkOrder((short)StartAddress)));
46 | pdu.AddRange(BitConverter.GetBytes(IPAddress.HostToNetworkOrder((short)NumberOfPoints)));
47 |
48 | return pdu.ToArray();
49 | }
50 | }
51 |
52 | ///
53 | /// Gets or sets a unique identifier assigned to a message when using the IP protocol.
54 | ///
55 | public ushort TransactionId { get; set; }
56 |
57 | ///
58 | /// Gets or sets the function code tells the server what kind of action to perform.
59 | ///
60 | public byte FunctionCode { get; set; }
61 |
62 | ///
63 | /// Gets or sets address of the slave (server).
64 | ///
65 | public byte SlaveAddress { get; set; }
66 |
67 | ///
68 | /// Gets or sets the start address.
69 | ///
70 | ///
71 | /// The start address.
72 | ///
73 | public ushort StartAddress { get; set; }
74 |
75 | ///
76 | /// Gets or sets the number of points.
77 | ///
78 | ///
79 | /// The number of points.
80 | ///
81 | public ushort NumberOfPoints { get; set; }
82 |
83 | ///
84 | /// Initializes a modbus message from the specified message frame.
85 | ///
86 | /// Bytes of Modbus frame.
87 | /// frame.
88 | /// Message frame does not contain enough bytes.
89 | public void Initialize(byte[] frame)
90 | {
91 | if (frame == null)
92 | {
93 | throw new ArgumentNullException(nameof(frame));
94 | }
95 |
96 | if (frame.Length < 6)
97 | {
98 | throw new FormatException("Message frame does not contain enough bytes.");
99 | }
100 |
101 | SlaveAddress = frame[0];
102 | FunctionCode = frame[1];
103 | StartAddress = (ushort)IPAddress.NetworkToHostOrder(BitConverter.ToInt16(frame, 2));
104 | NumberOfPoints = (ushort)IPAddress.NetworkToHostOrder(BitConverter.ToInt16(frame, 4));
105 | }
106 | }
107 |
--------------------------------------------------------------------------------
/src/ModbusRx.IntegrationTests/EnronFixture.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Chris Pulman. All rights reserved.
2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3 |
4 | #if SERIAL
5 | using ModbusRx.Extensions.Enron;
6 | using Xunit;
7 |
8 | namespace ModbusRx.IntegrationTests;
9 |
10 | ///
11 | /// EnronFixture.
12 | ///
13 | ///
14 | public class EnronFixture : NModbusSerialRtuMasterDl06SlaveFixture
15 | {
16 | ///
17 | /// Reads the holding registers32.
18 | ///
19 | [Fact]
20 | public virtual void ReadHoldingRegisters32()
21 | {
22 | var registers = Master?.ReadHoldingRegisters32(SlaveAddress, 104, 2);
23 | Assert.Equal(new uint[] { 0, 0 }, registers);
24 | }
25 |
26 | ///
27 | /// Reads the input registers32.
28 | ///
29 | [Fact]
30 | public virtual void ReadInputRegisters32()
31 | {
32 | var registers = Master?.ReadInputRegisters32(SlaveAddress, 104, 2);
33 | Assert.Equal(new uint[] { 0, 0 }, registers);
34 | }
35 |
36 | ///
37 | /// Writes the single register32.
38 | ///
39 | [Fact]
40 | public virtual void WriteSingleRegister32()
41 | {
42 | const ushort testAddress = 200;
43 | const uint testValue = 350;
44 |
45 | var originalValue = Master!.ReadHoldingRegisters32(SlaveAddress, testAddress, 1)[0];
46 | Master?.WriteSingleRegister32(SlaveAddress, testAddress, testValue);
47 | Assert.Equal(testValue, Master?.ReadHoldingRegisters32(SlaveAddress, testAddress, 1)[0]);
48 | Master?.WriteSingleRegister32(SlaveAddress, testAddress, originalValue);
49 | Assert.Equal(originalValue, Master!.ReadHoldingRegisters(SlaveAddress, testAddress, 1)[0]);
50 | }
51 |
52 | ///
53 | /// Writes the multiple registers32.
54 | ///
55 | [Fact]
56 | public virtual void WriteMultipleRegisters32()
57 | {
58 | const ushort testAddress = 120;
59 | var testValues = new uint[] { 10, 20, 30, 40, 50 };
60 |
61 | var originalValues = Master?.ReadHoldingRegisters32(SlaveAddress, testAddress, (ushort)testValues.Length);
62 | Master?.WriteMultipleRegisters32(SlaveAddress, testAddress, testValues);
63 | var newValues = Master?.ReadHoldingRegisters32(SlaveAddress, testAddress, (ushort)testValues.Length);
64 | Assert.Equal(testValues, newValues);
65 | Master?.WriteMultipleRegisters32(SlaveAddress, testAddress, originalValues!);
66 | }
67 | }
68 | #endif
69 |
--------------------------------------------------------------------------------
/src/ModbusRx.IntegrationTests/ModbusRx.IntegrationTests.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net48
5 | false
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/src/ModbusRx.IntegrationTests/ModbusRxIpMasterFixture.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Chris Pulman. All rights reserved.
2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3 |
4 | using System.Net.Sockets;
5 | using System.Threading;
6 | using CP.IO.Ports;
7 | using ModbusRx.Device;
8 | using Xunit;
9 |
10 | namespace ModbusRx.IntegrationTests;
11 |
12 | ///
13 | /// ModbusIpMasterFixture.
14 | ///
15 | public class ModbusRxIpMasterFixture
16 | {
17 | ///
18 | /// Overrides the timeout on TCP client.
19 | ///
20 | [Fact]
21 | public void OverrideTimeoutOnTcpClient()
22 | {
23 | var listener = new TcpListener(ModbusRxMasterFixture.TcpHost, ModbusRxMasterFixture.Port);
24 | using var slave = ModbusTcpSlave.CreateTcp(ModbusRxMasterFixture.SlaveAddress, listener);
25 | var slaveThread = new Thread(async () => await slave.ListenAsync());
26 | slaveThread.Start();
27 |
28 | var client = new TcpClientRx(ModbusRxMasterFixture.TcpHost.ToString(), ModbusRxMasterFixture.Port)
29 | {
30 | ReadTimeout = 1500,
31 | WriteTimeout = 3000
32 | };
33 | using var master = ModbusIpMaster.CreateIp(client);
34 | Assert.Equal(1500, client.ReadTimeout);
35 | Assert.Equal(3000, client.WriteTimeout);
36 | }
37 |
38 | ///
39 | /// Overrides the timeout on network stream.
40 | ///
41 | [Fact]
42 | public void OverrideTimeoutOnNetworkStream()
43 | {
44 | var listener = new TcpListener(ModbusRxMasterFixture.TcpHost, ModbusRxMasterFixture.Port);
45 | using var slave = ModbusTcpSlave.CreateTcp(ModbusRxMasterFixture.SlaveAddress, listener);
46 | var slaveThread = new Thread(async () => await slave.ListenAsync());
47 | slaveThread.Start();
48 |
49 | var client = new TcpClientRx(ModbusRxMasterFixture.TcpHost.ToString(), ModbusRxMasterFixture.Port);
50 | client.Stream.ReadTimeout = 1500;
51 | client.Stream.WriteTimeout = 3000;
52 | using var master = ModbusIpMaster.CreateIp(client);
53 | Assert.Equal(1500, client.ReadTimeout);
54 | Assert.Equal(3000, client.WriteTimeout);
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/src/ModbusRx.IntegrationTests/ModbusRxSerialAsciiMasterFixture.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Chris Pulman. All rights reserved.
2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3 |
4 | #if SERIAL
5 | using System;
6 | using ModbusRx.Device;
7 | using Xunit;
8 |
9 | namespace ModbusRx.IntegrationTests;
10 |
11 | ///
12 | /// NModbusSerialAsciiMasterFixture.
13 | ///
14 | public class ModbusRxSerialAsciiMasterFixture
15 | {
16 | ///
17 | /// ns the modbus ASCII master read timeout.
18 | ///
19 | [Fact]
20 | public void ModbusRxAsciiMaster_ReadTimeout()
21 | {
22 | var port = ModbusMasterFixture.CreateAndOpenSerialPort(ModbusMasterFixture.DefaultMasterSerialPortName);
23 | using IModbusSerialMaster master = ModbusSerialMaster.CreateAscii(port);
24 | master.Transport.ReadTimeout = master.Transport.WriteTimeout = 1000;
25 | Assert.Throws(() => master.ReadCoils(100, 1, 1));
26 | }
27 | }
28 | #endif
29 |
--------------------------------------------------------------------------------
/src/ModbusRx.IntegrationTests/ModbusRxSerialAsciiMasterJamodSerialAsciiSlaveFixture.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Chris Pulman. All rights reserved.
2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3 |
4 | #if JAMOD
5 | using ModbusRx.Device;
6 | using Xunit;
7 |
8 | namespace ModbusRx.IntegrationTests;
9 |
10 | ///
11 | /// ModbusRxSerialAsciiMasterJamodSerialAsciiSlaveFixture.
12 | ///
13 | ///
14 | public class ModbusRxSerialAsciiMasterJamodSerialAsciiSlaveFixture : ModbusMasterFixture
15 | {
16 | private const string Program = $"SerialSlave {DefaultSlaveSerialPortName} ASCII";
17 |
18 | ///
19 | /// Initializes a new instance of the class.
20 | ///
21 | public ModbusRxSerialAsciiMasterJamodSerialAsciiSlaveFixture()
22 | {
23 | StartJamodSlave(Program);
24 |
25 | MasterSerialPort = CreateAndOpenSerialPort(DefaultMasterSerialPortName);
26 | Master = ModbusSerialMaster.CreateAscii(MasterSerialPort);
27 | }
28 |
29 | ///
30 | /// Jamod slave does not support this function.
31 | ///
32 | public override void ReadWriteMultipleRegisters()
33 | {
34 | }
35 |
36 | ///
37 | /// Reads the coils.
38 | ///
39 | [Fact]
40 | public override void ReadCoils() =>
41 | base.ReadCoils();
42 | }
43 | #endif
44 |
--------------------------------------------------------------------------------
/src/ModbusRx.IntegrationTests/ModbusRxSerialAsciiMasterModbusRxSerialAsciiSlaveFixture.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Chris Pulman. All rights reserved.
2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3 |
4 | #if SERIAL
5 | using ModbusRx.Device;
6 | using Xunit;
7 |
8 | namespace ModbusRx.IntegrationTests;
9 |
10 | ///
11 | /// ModbusRxSerialAsciiMasterNModbusSerialAsciiSlaveFixture.
12 | ///
13 | ///
14 | public class ModbusRxSerialAsciiMasterModbusRxSerialAsciiSlaveFixture : ModbusSerialMasterFixture
15 | {
16 | ///
17 | /// Initializes a new instance of the class.
18 | ///
19 | public ModbusRxSerialAsciiMasterModbusRxSerialAsciiSlaveFixture()
20 | {
21 | MasterSerialPort = CreateAndOpenSerialPort(DefaultMasterSerialPortName);
22 | Master = ModbusSerialMaster.CreateAscii(MasterSerialPort);
23 | SetupSlaveSerialPort();
24 | Slave = ModbusSerialSlave.CreateAscii(SlaveAddress, SlaveSerialPort!);
25 |
26 | StartSlave();
27 | }
28 |
29 | ///
30 | /// Reads the coils.
31 | ///
32 | [Fact]
33 | public override void ReadCoils() =>
34 | base.ReadCoils();
35 |
36 | ///
37 | /// Reads the inputs.
38 | ///
39 | [Fact]
40 | public override void ReadInputs() =>
41 | base.ReadInputs();
42 |
43 | ///
44 | /// Reads the holding registers.
45 | ///
46 | [Fact]
47 | public override void ReadHoldingRegisters() =>
48 | base.ReadHoldingRegisters();
49 |
50 | ///
51 | /// Reads the input registers.
52 | ///
53 | [Fact]
54 | public override void ReadInputRegisters() =>
55 | base.ReadInputRegisters();
56 |
57 | ///
58 | /// Writes the single coil.
59 | ///
60 | [Fact]
61 | public override void WriteSingleCoil() =>
62 | base.WriteSingleCoil();
63 |
64 | ///
65 | /// Writes the multiple coils.
66 | ///
67 | [Fact]
68 | public override void WriteMultipleCoils() =>
69 | base.WriteMultipleCoils();
70 |
71 | ///
72 | /// Writes the single register.
73 | ///
74 | [Fact]
75 | public override void WriteSingleRegister() =>
76 | base.WriteSingleRegister();
77 |
78 | ///
79 | /// Writes the multiple registers.
80 | ///
81 | [Fact]
82 | public override void WriteMultipleRegisters() =>
83 | base.WriteMultipleRegisters();
84 |
85 | ///
86 | /// Reads the write multiple registers.
87 | ///
88 | [Fact]
89 | public override void ReadWriteMultipleRegisters() =>
90 | base.ReadWriteMultipleRegisters();
91 |
92 | ///
93 | /// Returns the query data.
94 | ///
95 | [Fact]
96 | public override void ReturnQueryData() =>
97 | base.ReturnQueryData();
98 | }
99 | #endif
100 |
--------------------------------------------------------------------------------
/src/ModbusRx.IntegrationTests/ModbusRxSerialMasterFixture.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Chris Pulman. All rights reserved.
2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3 |
4 | using ModbusRx.Device;
5 | using Xunit;
6 |
7 | namespace ModbusRx.IntegrationTests;
8 |
9 | ///
10 | /// ModbusSerialMasterFixture.
11 | ///
12 | ///
13 | public abstract class ModbusRxSerialMasterFixture : ModbusRxMasterFixture
14 | {
15 | ///
16 | /// Returns the query data.
17 | ///
18 | [Fact]
19 | public virtual void ReturnQueryData()
20 | {
21 | Assert.True(((ModbusSerialMaster)Master!).ReturnQueryData(SlaveAddress, 18));
22 | Assert.True(((ModbusSerialMaster)Master).ReturnQueryData(SlaveAddress, 5));
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/ModbusRx.IntegrationTests/ModbusRxSerialRtuMasterDl06SlaveFixture.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Chris Pulman. All rights reserved.
2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3 |
4 | #if SERIAL
5 | using ModbusRx.Device;
6 | using Xunit;
7 |
8 | namespace ModbusRx.IntegrationTests;
9 |
10 | ///
11 | /// ModbusRxSerialRtuMasterDl06SlaveFixture.
12 | ///
13 | ///
14 | public class ModbusRxSerialRtuMasterDl06SlaveFixture : ModbusSerialMasterFixture
15 | {
16 | ///
17 | /// Initializes a new instance of the class.
18 | ///
19 | public ModbusRxSerialRtuMasterDl06SlaveFixture()
20 | {
21 | MasterSerialPort = CreateAndOpenSerialPort("COM1");
22 | Master = ModbusSerialMaster.CreateRtu(MasterSerialPort);
23 | }
24 |
25 | ///
26 | /// Not supported by the DL06.
27 | ///
28 | public override void ReadWriteMultipleRegisters()
29 | {
30 | }
31 |
32 | ///
33 | /// Not supported by the DL06.
34 | ///
35 | public override void ReturnQueryData()
36 | {
37 | }
38 |
39 | ///
40 | /// Reads the coils.
41 | ///
42 | [Fact]
43 | public override void ReadCoils() =>
44 | base.ReadCoils();
45 | }
46 | #endif
47 |
--------------------------------------------------------------------------------
/src/ModbusRx.IntegrationTests/ModbusRxSerialRtuMasterFixture.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Chris Pulman. All rights reserved.
2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3 |
4 | #if SERIAL
5 | using ModbusRx.Device;
6 | using Xunit;
7 |
8 | namespace ModbusRx.IntegrationTests;
9 |
10 | ///
11 | /// ModbusRxSerialRtuMasterFixture.
12 | ///
13 | public class ModbusRxSerialRtuMasterFixture
14 | {
15 | ///
16 | /// ns the modbus rtu master read timeout.
17 | ///
18 | [Fact]
19 | public void ModbusRxRtuMaster_ReadTimeout()
20 | {
21 | var port = ModbusMasterFixture.CreateAndOpenSerialPort(ModbusMasterFixture.DefaultMasterSerialPortName);
22 | using var master = ModbusSerialMaster.CreateRtu(port);
23 | master.Transport.ReadTimeout = master.Transport.WriteTimeout = 1000;
24 | master.ReadCoils(100, 1, 1);
25 | }
26 | }
27 | #endif
28 |
--------------------------------------------------------------------------------
/src/ModbusRx.IntegrationTests/ModbusRxSerialRtuMasterModbusRxSerialRtuSlaveFixture.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Chris Pulman. All rights reserved.
2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3 |
4 | #if SERIAL
5 | using ModbusRx.Device;
6 | using Xunit;
7 |
8 | namespace ModbusRx.IntegrationTests;
9 |
10 | ///
11 | /// NModbusSerialRtuMasterNModbusSerialRtuSlaveFixture.
12 | ///
13 | ///
14 | public class NModbusSerialRtuMasterNModbusSerialRtuSlaveFixture : ModbusSerialMasterFixture
15 | {
16 | ///
17 | /// Initializes a new instance of the class.
18 | ///
19 | public NModbusSerialRtuMasterNModbusSerialRtuSlaveFixture()
20 | {
21 | SetupSlaveSerialPort();
22 | Slave = ModbusSerialSlave.CreateRtu(SlaveAddress, SlaveSerialPort!);
23 | StartSlave();
24 |
25 | MasterSerialPort = CreateAndOpenSerialPort(DefaultMasterSerialPortName);
26 | Master = ModbusSerialMaster.CreateRtu(MasterSerialPort);
27 | }
28 |
29 | ///
30 | /// Reads the coils.
31 | ///
32 | [Fact]
33 | public override void ReadCoils() =>
34 | base.ReadCoils();
35 |
36 | ///
37 | /// Reads the holding registers.
38 | ///
39 | [Fact]
40 | public override void ReadHoldingRegisters() =>
41 | base.ReadHoldingRegisters();
42 |
43 | ///
44 | /// Reads the inputs.
45 | ///
46 | [Fact]
47 | public override void ReadInputs() =>
48 | base.ReadInputs();
49 |
50 | ///
51 | /// Writes the single coil.
52 | ///
53 | [Fact]
54 | public override void WriteSingleCoil() =>
55 | base.WriteSingleCoil();
56 |
57 | ///
58 | /// Writes the multiple coils.
59 | ///
60 | [Fact]
61 | public override void WriteMultipleCoils() =>
62 | base.WriteMultipleCoils();
63 |
64 | ///
65 | /// Writes the single register.
66 | ///
67 | [Fact]
68 | public override void WriteSingleRegister() =>
69 | base.WriteSingleRegister();
70 |
71 | ///
72 | /// Writes the multiple registers.
73 | ///
74 | [Fact]
75 | public override void WriteMultipleRegisters() =>
76 | base.WriteMultipleRegisters();
77 |
78 | ///
79 | /// Reads the write multiple registers.
80 | ///
81 | [Fact(Skip = "Need to fix RTU slave for this function code")]
82 | public override void ReadWriteMultipleRegisters() =>
83 | base.ReadWriteMultipleRegisters();
84 |
85 | ///
86 | /// Returns the query data.
87 | ///
88 | [Fact]
89 | public override void ReturnQueryData() =>
90 | base.ReturnQueryData();
91 | }
92 | #endif
93 |
--------------------------------------------------------------------------------
/src/ModbusRx.IntegrationTests/ModbusRxSerialRtuSlaveFixture.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Chris Pulman. All rights reserved.
2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3 |
4 | #if SERIAL
5 |
6 | using System.Threading;
7 | using ModbusRx.Data;
8 | using ModbusRx.Device;
9 | using Xunit;
10 |
11 | namespace ModbusRx.IntegrationTests;
12 |
13 | ///
14 | /// ModbusRxSerialRtuSlaveFixture.
15 | ///
16 | public class ModbusRxSerialRtuSlaveFixture
17 | {
18 | ///
19 | /// ns the modbus serial rtu slave bonus character verify timeout.
20 | ///
21 | [Fact]
22 | public void ModbusRxSerialRtuSlave_BonusCharacter_VerifyTimeout()
23 | {
24 | var masterPort = ModbusMasterFixture.CreateAndOpenSerialPort(ModbusMasterFixture.DefaultMasterSerialPortName);
25 | var slavePort = ModbusMasterFixture.CreateAndOpenSerialPort(ModbusMasterFixture.DefaultSlaveSerialPortName);
26 |
27 | using var master = ModbusSerialMaster.CreateRtu(masterPort);
28 | using var slave = ModbusSerialSlave.CreateRtu(1, slavePort);
29 | master.Transport.ReadTimeout = master.Transport.WriteTimeout = 1000;
30 | slave.DataStore = DataStoreFactory.CreateTestDataStore();
31 |
32 | var slaveThread = new Thread(async () => await slave.ListenAsync())
33 | {
34 | IsBackground = true
35 | };
36 | slaveThread.Start();
37 |
38 | // assert successful communication
39 | Assert.Equal(new bool[] { false, true }, master.ReadCoils(1, 1, 2));
40 |
41 | // write "bonus" character
42 | masterPort.Write("*");
43 |
44 | // assert successful communication
45 | Assert.Equal(new bool[] { false, true }, master.ReadCoils(1, 1, 2));
46 | }
47 | }
48 | #endif
49 |
--------------------------------------------------------------------------------
/src/ModbusRx.IntegrationTests/ModbusRxTcpMasterJamodTcpSlaveFixture.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Chris Pulman. All rights reserved.
2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3 |
4 | #if JAMOD
5 | using System.Net.Sockets;
6 | using ModbusRx.Device;
7 |
8 | namespace ModbusRx.IntegrationTests;
9 |
10 | ///
11 | /// NModbusTcpMasterJamodTcpSlaveFixture.
12 | ///
13 | ///
14 | public class ModbusRxTcpMasterJamodTcpSlaveFixture : ModbusMasterFixture
15 | {
16 | ///
17 | /// Initializes a new instance of the class.
18 | ///
19 | public ModbusRxTcpMasterJamodTcpSlaveFixture()
20 | {
21 | var program = $"TcpSlave {Port}";
22 | StartJamodSlave(program);
23 |
24 | MasterTcp = new TcpClientRx(TcpHost.ToString(), Port);
25 | Master = ModbusIpMaster.CreateIp(MasterTcp);
26 | }
27 |
28 | ///
29 | /// Not supported by the Jamod Slave.
30 | ///
31 | public override void ReadWriteMultipleRegisters()
32 | {
33 | }
34 | }
35 | #endif
36 |
--------------------------------------------------------------------------------
/src/ModbusRx.IntegrationTests/ModbusRxTcpMasterNModbusTcpSlaveFixture.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Chris Pulman. All rights reserved.
2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3 |
4 | using System.Net.Sockets;
5 | using CP.IO.Ports;
6 | using ModbusRx.Device;
7 |
8 | namespace ModbusRx.IntegrationTests;
9 |
10 | ///
11 | /// NModbusTcpMasterNModbusTcpSlaveFixture.
12 | ///
13 | ///
14 | public class ModbusRxTcpMasterNModbusTcpSlaveFixture : ModbusRxMasterFixture
15 | {
16 | ///
17 | /// Initializes a new instance of the class.
18 | ///
19 | public ModbusRxTcpMasterNModbusTcpSlaveFixture()
20 | {
21 | SlaveTcp = new TcpListener(TcpHost, Port);
22 | SlaveTcp.Start();
23 | Slave = ModbusTcpSlave.CreateTcp(SlaveAddress, SlaveTcp);
24 | StartSlave();
25 |
26 | MasterTcp = new TcpClientRx(TcpHost.ToString(), Port);
27 | Master = ModbusIpMaster.CreateIp(MasterTcp);
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/ModbusRx.IntegrationTests/ModbusRxUdpMasterModbusRxUdpSlaveFixture.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Chris Pulman. All rights reserved.
2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3 |
4 | using CP.IO.Ports;
5 | using ModbusRx.Device;
6 |
7 | namespace ModbusRx.IntegrationTests;
8 |
9 | ///
10 | /// NModbusUdpMasterNModbusUdpSlaveFixture.
11 | ///
12 | ///
13 | public class ModbusRxUdpMasterModbusRxUdpSlaveFixture : ModbusRxMasterFixture
14 | {
15 | ///
16 | /// Initializes a new instance of the class.
17 | ///
18 | public ModbusRxUdpMasterModbusRxUdpSlaveFixture()
19 | {
20 | SlaveUdp = new UdpClientRx(Port);
21 | Slave = ModbusUdpSlave.CreateUdp(SlaveUdp);
22 | StartSlave();
23 |
24 | MasterUdp = new UdpClientRx();
25 | MasterUdp.Connect(DefaultModbusIPEndPoint);
26 | Master = ModbusIpMaster.CreateIp(MasterUdp);
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/ModbusRx.IntegrationTests/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Chris Pulman. All rights reserved.
2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3 |
4 | using Xunit;
5 |
6 | [assembly: CollectionBehavior(CollectionBehavior.CollectionPerAssembly, DisableTestParallelization = true, MaxParallelThreads = 1)]
7 |
--------------------------------------------------------------------------------
/src/ModbusRx.IntegrationTests/TestCases.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Chris Pulman. All rights reserved.
2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3 |
4 | using System;
5 | using System.IO.Ports;
6 | using System.Net;
7 | using System.Net.Sockets;
8 | using System.Threading;
9 | using System.Threading.Tasks;
10 | using CP.IO.Ports;
11 | using ModbusRx.Data;
12 | using ModbusRx.Device;
13 |
14 | namespace ModbusRx.IntegrationTests;
15 |
16 | internal static class TestCases
17 | {
18 | public static async void Serial()
19 | {
20 | using var masterPort = new SerialPortRx("COM2");
21 | using var slavePort = new SerialPortRx("COM1");
22 |
23 | // configure serial ports
24 | masterPort.BaudRate = slavePort.BaudRate = 9600;
25 | masterPort.DataBits = slavePort.DataBits = 8;
26 | masterPort.Parity = slavePort.Parity = Parity.None;
27 | masterPort.StopBits = slavePort.StopBits = StopBits.One;
28 | await masterPort.Open();
29 | await slavePort.Open();
30 |
31 | using var slave = ModbusSerialSlave.CreateRtu(1, slavePort);
32 | StartSlave(slave);
33 |
34 | // create modbus master
35 | using var master = ModbusSerialMaster.CreateRtu(masterPort);
36 | await ReadRegistersAsync(master);
37 | }
38 |
39 | public static async void Tcp()
40 | {
41 | var slaveClient = new TcpListener(new IPAddress(new byte[] { 127, 0, 0, 1 }), 502);
42 | using var slave = ModbusTcpSlave.CreateTcp((byte)1, slaveClient);
43 | StartSlave(slave);
44 |
45 | var address = new IPAddress(new byte[] { 127, 0, 0, 1 });
46 | var masterClient = new TcpClientRx(address.ToString(), 502);
47 |
48 | using var master = ModbusIpMaster.CreateIp(masterClient);
49 | await ReadRegistersAsync(master);
50 | }
51 |
52 | public static async void Udp()
53 | {
54 | var slaveClient = new UdpClientRx(502);
55 | using var slave = ModbusUdpSlave.CreateUdp(slaveClient);
56 | StartSlave(slave);
57 |
58 | var masterClient = new UdpClientRx();
59 | var endPoint = new IPEndPoint(new IPAddress(new byte[] { 127, 0, 0, 1 }), 502);
60 | masterClient.Connect(endPoint);
61 |
62 | using var master = ModbusIpMaster.CreateIp(masterClient);
63 | await ReadRegistersAsync(master);
64 | }
65 |
66 | public static void StartSlave(ModbusSlave slave)
67 | {
68 | slave.DataStore = DataStoreFactory.CreateTestDataStore();
69 | var slaveThread = new Thread(async () => await slave.ListenAsync());
70 | slaveThread.Start();
71 | }
72 |
73 | public static async Task ReadRegistersAsync(IModbusMaster master)
74 | {
75 | var result = await master.ReadHoldingRegistersAsync(1, 0, 5);
76 |
77 | for (var i = 0; i < 5; i++)
78 | {
79 | if (result[i] != i + 1)
80 | {
81 | throw new Exception();
82 | }
83 | }
84 | }
85 | }
86 |
--------------------------------------------------------------------------------
/src/ModbusRx.UnitTests/Data/BoolModbusDataCollectionFixture.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Chris Pulman. All rights reserved.
2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3 |
4 | using System.Collections.ObjectModel;
5 | using ModbusRx.Data;
6 | using Xunit;
7 |
8 | namespace ModbusRx.UnitTests.Data;
9 |
10 | ///
11 | /// BoolModbusDataCollectionFixture.
12 | ///
13 | public class BoolModbusDataCollectionFixture : ModbusDataCollectionFixture
14 | {
15 | ///
16 | /// Removes from read only.
17 | ///
18 | [Fact]
19 | public void Remove_FromReadOnly()
20 | {
21 | bool[] source = { false, false, false, true, false, false };
22 | var col = new ModbusDataCollection(new ReadOnlyCollection(source));
23 | var expectedCount = source.Length;
24 |
25 | Assert.True(col.Remove(source[3]));
26 |
27 | Assert.Equal(expectedCount, col.Count);
28 | }
29 |
30 | ///
31 | /// Gets the array.
32 | ///
33 | /// A bool.
34 | protected override bool[] GetArray() =>
35 | new[] { false, false, true, false, false };
36 |
37 | ///
38 | /// Gets the non existent element.
39 | ///
40 | /// A bool.
41 | protected override bool GetNonExistentElement() => true;
42 | }
43 |
--------------------------------------------------------------------------------
/src/ModbusRx.UnitTests/Data/DataStoreEventArgsFixture.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Chris Pulman. All rights reserved.
2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3 |
4 | using System;
5 | using System.Linq;
6 | using ModbusRx.Data;
7 | using Xunit;
8 |
9 | namespace ModbusRx.UnitTests.Data;
10 |
11 | ///
12 | /// DataStoreEventArgsFixture.
13 | ///
14 | public class DataStoreEventArgsFixture
15 | {
16 | ///
17 | /// Creates the data store event arguments.
18 | ///
19 | [Fact]
20 | public void CreateDataStoreEventArgs()
21 | {
22 | var eventArgs = DataStoreEventArgs.CreateDataStoreEventArgs(5, ModbusDataType.HoldingRegister, new ushort[] { 1, 2, 3 });
23 | Assert.Equal(ModbusDataType.HoldingRegister, eventArgs.ModbusDataType);
24 | Assert.Equal(5, eventArgs.StartAddress);
25 | Assert.Equal(new ushort[] { 1, 2, 3 }, eventArgs.Data!.B?.ToArray());
26 | }
27 |
28 | ///
29 | /// Creates the type of the data store event arguments invalid.
30 | ///
31 | [Fact]
32 | public void CreateDataStoreEventArgs_InvalidType() =>
33 | Assert.Throws(() => DataStoreEventArgs.CreateDataStoreEventArgs(5, ModbusDataType.HoldingRegister, new int[] { 1, 2, 3 }));
34 |
35 | ///
36 | /// Creates the data store event arguments data null.
37 | ///
38 | [Fact]
39 | public void CreateDataStoreEventArgs_DataNull() =>
40 | Assert.Throws(() =>
41 | DataStoreEventArgs.CreateDataStoreEventArgs(5, ModbusDataType.HoldingRegister, default(ushort[])!));
42 | }
43 |
--------------------------------------------------------------------------------
/src/ModbusRx.UnitTests/Data/RegisterCollectionFixture.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Chris Pulman. All rights reserved.
2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3 |
4 | using ModbusRx.Data;
5 | using Xunit;
6 |
7 | namespace ModbusRx.UnitTests.Data;
8 |
9 | ///
10 | /// RegisterCollectionFixture.
11 | ///
12 | public class RegisterCollectionFixture
13 | {
14 | ///
15 | /// Bytes the count.
16 | ///
17 | [Fact]
18 | public void ByteCount()
19 | {
20 | var col = new RegisterCollection(1, 2, 3);
21 | Assert.Equal(6, col.ByteCount);
22 | }
23 |
24 | ///
25 | /// Creates new registercollection.
26 | ///
27 | [Fact]
28 | public void NewRegisterCollection()
29 | {
30 | var col = new RegisterCollection(5, 3, 4, 6);
31 | Assert.NotNull(col);
32 | Assert.Equal(4, col.Count);
33 | Assert.Equal(5, col[0]);
34 | }
35 |
36 | ///
37 | /// Creates new registercollectionfrombytes.
38 | ///
39 | [Fact]
40 | public void NewRegisterCollectionFromBytes()
41 | {
42 | var col = new RegisterCollection(new byte[] { 0, 1, 0, 2, 0, 3 });
43 | Assert.NotNull(col);
44 | Assert.Equal(3, col.Count);
45 | Assert.Equal(1, col[0]);
46 | Assert.Equal(2, col[1]);
47 | Assert.Equal(3, col[2]);
48 | }
49 |
50 | ///
51 | /// Registers the collection network bytes.
52 | ///
53 | [Fact]
54 | public void RegisterCollectionNetworkBytes()
55 | {
56 | var col = new RegisterCollection(5, 3, 4, 6);
57 | var bytes = col.NetworkBytes;
58 | Assert.NotNull(bytes);
59 | Assert.Equal(8, bytes.Length);
60 | Assert.Equal(new byte[] { 0, 5, 0, 3, 0, 4, 0, 6 }, bytes);
61 | }
62 |
63 | ///
64 | /// Registers the collection empty.
65 | ///
66 | [Fact]
67 | public void RegisterCollectionEmpty()
68 | {
69 | var col = new RegisterCollection();
70 | Assert.NotNull(col);
71 | Assert.Empty(col.NetworkBytes);
72 | }
73 |
74 | ///
75 | /// Modifies the register.
76 | ///
77 | [Fact]
78 | public void ModifyRegister()
79 | {
80 | var col = new RegisterCollection(1, 2, 3, 4)
81 | {
82 | [0] = 5
83 | };
84 | }
85 |
86 | ///
87 | /// Adds the register.
88 | ///
89 | [Fact]
90 | public void AddRegister()
91 | {
92 | var col = new RegisterCollection();
93 | Assert.Empty(col);
94 |
95 | col.Add(45);
96 | Assert.Single(col);
97 | }
98 |
99 | ///
100 | /// Removes the register.
101 | ///
102 | [Fact]
103 | public void RemoveRegister()
104 | {
105 | var col = new RegisterCollection(3, 4, 5);
106 | Assert.Equal(3, col.Count);
107 | col.RemoveAt(2);
108 | Assert.Equal(2, col.Count);
109 | }
110 | }
111 |
--------------------------------------------------------------------------------
/src/ModbusRx.UnitTests/Data/UshortModbusDataCollectionFixture.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Chris Pulman. All rights reserved.
2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3 |
4 | using System.Collections.ObjectModel;
5 | using ModbusRx.Data;
6 | using Xunit;
7 |
8 | namespace ModbusRx.UnitTests.Data;
9 |
10 | ///
11 | /// UshortModbusDataCollectionFixture.
12 | ///
13 | public class UshortModbusDataCollectionFixture : ModbusDataCollectionFixture
14 | {
15 | ///
16 | /// Removes from read only.
17 | ///
18 | [Fact]
19 | public void Remove_FromReadOnly()
20 | {
21 | var source = GetArray();
22 | var col = new ModbusDataCollection(new ReadOnlyCollection(source));
23 | var expectedCount = source.Length;
24 |
25 | Assert.False(col.Remove(GetNonExistentElement()));
26 | Assert.True(col.Remove(source[3]));
27 | Assert.Equal(expectedCount, col.Count);
28 | }
29 |
30 | ///
31 | /// Gets the array.
32 | ///
33 | /// A ushort.
34 | protected override ushort[] GetArray() =>
35 | new ushort[] { 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 };
36 |
37 | ///
38 | /// Gets the non existent element.
39 | ///
40 | /// A ushort.
41 | protected override ushort GetNonExistentElement() => 42;
42 | }
43 |
--------------------------------------------------------------------------------
/src/ModbusRx.UnitTests/Device/TcpConnectionEventArgsFixture.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Chris Pulman. All rights reserved.
2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3 |
4 | using System;
5 | using ModbusRx.Device;
6 | using Xunit;
7 |
8 | namespace ModbusRx.UnitTests.Device;
9 |
10 | ///
11 | /// TcpConnectionEventArgsFixture.
12 | ///
13 | public class TcpConnectionEventArgsFixture
14 | {
15 | ///
16 | /// TCPs the connection event arguments null end point.
17 | ///
18 | [Fact]
19 | public void TcpConnectionEventArgs_NullEndPoint() =>
20 | Assert.Throws(() => new TcpConnectionEventArgs(null!));
21 |
22 | ///
23 | /// TCPs the connection event arguments empty end point.
24 | ///
25 | [Fact]
26 | public void TcpConnectionEventArgs_EmptyEndPoint() =>
27 | Assert.Throws(() => new TcpConnectionEventArgs(string.Empty));
28 |
29 | ///
30 | /// TCPs the connection event arguments.
31 | ///
32 | [Fact]
33 | public void TcpConnectionEventArgs()
34 | {
35 | var args = new TcpConnectionEventArgs("foo");
36 |
37 | Assert.Equal("foo", args.EndPoint);
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/src/ModbusRx.UnitTests/IO/EmptyTransportFixture.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Chris Pulman. All rights reserved.
2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3 |
4 | using System;
5 | using System.Threading.Tasks;
6 | using ModbusRx.IO;
7 | using ModbusRx.Message;
8 | using Xunit;
9 |
10 | namespace ModbusRx.UnitTests.IO;
11 |
12 | ///
13 | /// EmptyTransportFixture.
14 | ///
15 | public static class EmptyTransportFixture
16 | {
17 | ///
18 | /// Negatives this instance.
19 | ///
20 | /// A representing the asynchronous unit test.
21 | [Fact]
22 | public static async Task NegativeAsync()
23 | {
24 | var transport = new EmptyTransport();
25 | await Assert.ThrowsAsync(() => transport.ReadRequest());
26 | await Assert.ThrowsAsync(() => transport.ReadResponse());
27 | Assert.Throws(() => transport.BuildMessageFrame(null!));
28 | Assert.Throws(() => transport.Write(null!));
29 | Assert.Throws(() => transport.OnValidateResponse(null!, null!));
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/ModbusRx.UnitTests/IO/UdpClientAdapterFixture.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Chris Pulman. All rights reserved.
2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3 |
4 | using System;
5 | using System.Threading.Tasks;
6 | using CP.IO.Ports;
7 | using ModbusRx.IO;
8 | using Xunit;
9 |
10 | namespace ModbusRx.UnitTests.IO;
11 |
12 | ///
13 | /// UdpClientAdapterFixture.
14 | ///
15 | public class UdpClientAdapterFixture
16 | {
17 | ///
18 | /// Reads the argument validation.
19 | ///
20 | /// A representing the asynchronous unit test.
21 | [Fact]
22 | public async Task Read_ArgumentValidationAsync()
23 | {
24 | var adapter = new UdpClientAdapter(new UdpClientRx());
25 |
26 | // buffer
27 | await Assert.ThrowsAsync(() => adapter.ReadAsync(null!, 1, 1));
28 |
29 | // offset
30 | await Assert.ThrowsAsync(() => adapter.ReadAsync(new byte[2], -1, 2));
31 | await Assert.ThrowsAsync(() => adapter.ReadAsync(new byte[2], 3, 3));
32 |
33 | await Assert.ThrowsAsync(() => adapter.ReadAsync(new byte[2], 0, -1));
34 | await Assert.ThrowsAsync(() => adapter.ReadAsync(new byte[2], 1, 2));
35 | }
36 |
37 | ///
38 | /// Writes the argument validation.
39 | ///
40 | [Fact]
41 | public void Write_ArgumentValidation()
42 | {
43 | var adapter = new UdpClientAdapter(new UdpClientRx());
44 |
45 | // buffer
46 | Assert.Throws(() => adapter.Write(null!, 1, 1));
47 |
48 | // offset
49 | Assert.Throws(() => adapter.Write(new byte[2], -1, 2));
50 | Assert.Throws(() => adapter.Write(new byte[2], 3, 3));
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/src/ModbusRx.UnitTests/InvalidModbusRequestExceptionFixture.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Chris Pulman. All rights reserved.
2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3 |
4 | using System.IO;
5 | using Xunit;
6 |
7 | namespace ModbusRx.UnitTests;
8 |
9 | ///
10 | /// InvalidModbusRequestExceptionFixture.
11 | ///
12 | public class InvalidModbusRequestExceptionFixture
13 | {
14 | ///
15 | /// Constructors the with exception code.
16 | ///
17 | [Fact]
18 | public void ConstructorWithExceptionCode()
19 | {
20 | var e = new InvalidModbusRequestException(Modbus.SlaveDeviceBusy);
21 | Assert.Equal($"Modbus exception code {Modbus.SlaveDeviceBusy}.", e.Message);
22 | Assert.Equal(Modbus.SlaveDeviceBusy, e.ExceptionCode);
23 | Assert.Null(e.InnerException);
24 | }
25 |
26 | ///
27 | /// Constructors the with exception code and inner exception.
28 | ///
29 | [Fact]
30 | public void ConstructorWithExceptionCodeAndInnerException()
31 | {
32 | var inner = new IOException("Bar");
33 | var e = new InvalidModbusRequestException(42, inner);
34 | Assert.Equal("Modbus exception code 42.", e.Message);
35 | Assert.Equal(42, e.ExceptionCode);
36 | Assert.Same(inner, e.InnerException);
37 | }
38 |
39 | ///
40 | /// Constructors the with message and exception code.
41 | ///
42 | [Fact]
43 | public void ConstructorWithMessageAndExceptionCode()
44 | {
45 | var e = new InvalidModbusRequestException("Hello World", Modbus.IllegalFunction);
46 | Assert.Equal("Hello World", e.Message);
47 | Assert.Equal(Modbus.IllegalFunction, e.ExceptionCode);
48 | Assert.Null(e.InnerException);
49 | }
50 |
51 | ///
52 | /// Constructors the with custom message and slave exception response.
53 | ///
54 | [Fact]
55 | public void ConstructorWithCustomMessageAndSlaveExceptionResponse()
56 | {
57 | var inner = new IOException("Bar");
58 | var e = new InvalidModbusRequestException("Hello World", Modbus.IllegalDataAddress, inner);
59 | Assert.Equal("Hello World", e.Message);
60 | Assert.Equal(Modbus.IllegalDataAddress, e.ExceptionCode);
61 | Assert.Same(inner, e.InnerException);
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/src/ModbusRx.UnitTests/Message/DiagnosticsRequestResponseFixture.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Chris Pulman. All rights reserved.
2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3 |
4 | using ModbusRx.Data;
5 | using ModbusRx.Message;
6 | using Xunit;
7 |
8 | namespace ModbusRx.UnitTests.Message;
9 |
10 | ///
11 | /// DiagnosticsRequestResponseFixture.
12 | ///
13 | public class DiagnosticsRequestResponseFixture
14 | {
15 | ///
16 | /// Converts to string_test.
17 | ///
18 | [Fact]
19 | public void ToString_Test()
20 | {
21 | DiagnosticsRequestResponse response;
22 |
23 | response = new DiagnosticsRequestResponse(Modbus.DiagnosticsReturnQueryData, 3, new RegisterCollection(5));
24 | Assert.Equal("Diagnostics message, sub-function return query data - {5}.", response.ToString());
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/ModbusRx.UnitTests/Message/MessageUtility.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Chris Pulman. All rights reserved.
2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3 |
4 | using System;
5 | using System.Collections.Generic;
6 |
7 | namespace ModbusRx.UnitTests.Message;
8 |
9 | ///
10 | /// MessageUtility.
11 | ///
12 | public static class MessageUtility
13 | {
14 | ///
15 | /// Creates a collection initialized to a default value.
16 | ///
17 | /// The Key.
18 | /// The type of the v.
19 | /// The default value.
20 | /// The size.
21 | /// A value of T.
22 | /// size - Collection size cannot be less than 0.
23 | public static T CreateDefaultCollection(TV defaultValue, int size)
24 | where T : ICollection, new()
25 | {
26 | if (size < 0)
27 | {
28 | throw new ArgumentOutOfRangeException(nameof(size), "Collection size cannot be less than 0.");
29 | }
30 |
31 | var col = new T();
32 |
33 | for (var i = 0; i < size; i++)
34 | {
35 | col.Add(defaultValue);
36 | }
37 |
38 | return col;
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/src/ModbusRx.UnitTests/Message/ModbusMessageFixture.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Chris Pulman. All rights reserved.
2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3 |
4 | using System.Linq;
5 | using System.Reflection;
6 | using ModbusRx.Message;
7 | using Xunit;
8 |
9 | namespace ModbusRx.UnitTests.Message;
10 |
11 | ///
12 | /// ModbusMessageFixture.
13 | ///
14 | public class ModbusMessageFixture
15 | {
16 | ///
17 | /// Protocols the data unit read coils request.
18 | ///
19 | [Fact]
20 | public void ProtocolDataUnitReadCoilsRequest()
21 | {
22 | AbstractModbusMessage message = new ReadCoilsInputsRequest(Modbus.ReadCoils, 1, 100, 9);
23 | byte[] expectedResult = { Modbus.ReadCoils, 0, 100, 0, 9 };
24 | Assert.Equal(expectedResult, message.ProtocolDataUnit);
25 | }
26 |
27 | ///
28 | /// Messages the frame read coils request.
29 | ///
30 | [Fact]
31 | public void MessageFrameReadCoilsRequest()
32 | {
33 | AbstractModbusMessage message = new ReadCoilsInputsRequest(Modbus.ReadCoils, 1, 2, 3);
34 | byte[] expectedMessageFrame = { 1, Modbus.ReadCoils, 0, 2, 0, 3 };
35 | Assert.Equal(expectedMessageFrame, message.MessageFrame);
36 | }
37 |
38 | ///
39 | /// Modbuses the message to string overriden.
40 | ///
41 | [Fact]
42 | public void ModbusMessageToStringOverriden()
43 | {
44 | var messageTypes = from message in typeof(AbstractModbusMessage).GetTypeInfo().Assembly.GetTypes()
45 | let typeInfo = message.GetTypeInfo()
46 | where !typeInfo.IsAbstract && typeInfo.IsSubclassOf(typeof(AbstractModbusMessage))
47 | select message;
48 |
49 | foreach (var messageType in messageTypes)
50 | {
51 | Assert.NotNull(
52 | messageType.GetMethod("ToString", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly));
53 | }
54 | }
55 |
56 | ///
57 | /// Asserts the modbus message properties are equal.
58 | ///
59 | /// The obj1.
60 | /// The obj2.
61 | internal static void AssertModbusMessagePropertiesAreEqual(IModbusMessage obj1, IModbusMessage obj2)
62 | {
63 | Assert.Equal(obj1.FunctionCode, obj2.FunctionCode);
64 | Assert.Equal(obj1.SlaveAddress, obj2.SlaveAddress);
65 | Assert.Equal(obj1.MessageFrame, obj2.MessageFrame);
66 | Assert.Equal(obj1.ProtocolDataUnit, obj2.ProtocolDataUnit);
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/src/ModbusRx.UnitTests/Message/ModbusMessageImplFixture.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Chris Pulman. All rights reserved.
2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3 |
4 | using System;
5 | using ModbusRx.Message;
6 | using Xunit;
7 |
8 | namespace ModbusRx.UnitTests.Message;
9 |
10 | ///
11 | /// ModbusMessageImplFixture.
12 | ///
13 | public class ModbusMessageImplFixture
14 | {
15 | ///
16 | /// Modbuses the message ctor initializes properties.
17 | ///
18 | [Fact]
19 | public void ModbusMessageCtorInitializesProperties()
20 | {
21 | var messageImpl = new ModbusMessageImpl(5, Modbus.ReadCoils);
22 | Assert.Equal(5, messageImpl.SlaveAddress);
23 | Assert.Equal(Modbus.ReadCoils, messageImpl.FunctionCode);
24 | }
25 |
26 | ///
27 | /// Initializes this instance.
28 | ///
29 | [Fact]
30 | public void Initialize()
31 | {
32 | var messageImpl = new ModbusMessageImpl();
33 | messageImpl.Initialize(new byte[] { 1, 2, 9, 9, 9, 9 });
34 | Assert.Equal(1, messageImpl.SlaveAddress);
35 | Assert.Equal(2, messageImpl.FunctionCode);
36 | }
37 |
38 | ///
39 | /// Checcks the initialize frame null.
40 | ///
41 | [Fact]
42 | public void ChecckInitializeFrameNull()
43 | {
44 | var messageImpl = new ModbusMessageImpl();
45 | Assert.Throws(() => messageImpl.Initialize(null!));
46 | }
47 |
48 | ///
49 | /// Initializes the invalid frame.
50 | ///
51 | [Fact]
52 | public void InitializeInvalidFrame()
53 | {
54 | var messageImpl = new ModbusMessageImpl();
55 | Assert.Throws(() => messageImpl.Initialize(new byte[] { 1 }));
56 | }
57 |
58 | ///
59 | /// Protocols the data unit.
60 | ///
61 | [Fact]
62 | public void ProtocolDataUnit()
63 | {
64 | var messageImpl = new ModbusMessageImpl(11, Modbus.ReadCoils);
65 | byte[] expectedResult = { Modbus.ReadCoils };
66 | Assert.Equal(expectedResult, messageImpl.ProtocolDataUnit);
67 | }
68 |
69 | ///
70 | /// Messages the frame.
71 | ///
72 | [Fact]
73 | public void MessageFrame()
74 | {
75 | var messageImpl = new ModbusMessageImpl(11, Modbus.ReadHoldingRegisters);
76 | byte[] expectedMessageFrame = { 11, Modbus.ReadHoldingRegisters };
77 | Assert.Equal(expectedMessageFrame, messageImpl.MessageFrame);
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/src/ModbusRx.UnitTests/Message/ModbusMessageWithDataFixture.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Chris Pulman. All rights reserved.
2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3 |
4 | using ModbusRx.Data;
5 | using ModbusRx.Message;
6 | using Xunit;
7 |
8 | namespace ModbusRx.UnitTests.Message;
9 |
10 | ///
11 | /// ModbusMessageWithDataFixture.
12 | ///
13 | public class ModbusMessageWithDataFixture
14 | {
15 | ///
16 | /// Modbuses the message with data fixture ctor initializes properties.
17 | ///
18 | [Fact]
19 | public void ModbusMessageWithDataFixtureCtorInitializesProperties()
20 | {
21 | AbstractModbusMessageWithData message = new ReadCoilsInputsResponse(Modbus.ReadCoils, 10, 1, new DiscreteCollection(true, false, true));
22 | Assert.Equal(Modbus.ReadCoils, message.FunctionCode);
23 | Assert.Equal(10, message.SlaveAddress);
24 | }
25 |
26 | ///
27 | /// Protocols the data unit read coils response.
28 | ///
29 | [Fact]
30 | public void ProtocolDataUnitReadCoilsResponse()
31 | {
32 | AbstractModbusMessageWithData message = new ReadCoilsInputsResponse(Modbus.ReadCoils, 1, 2, new DiscreteCollection(true));
33 | byte[] expectedResult = { 1, 2, 1 };
34 | Assert.Equal(expectedResult, message.ProtocolDataUnit);
35 | }
36 |
37 | ///
38 | /// Datas the read coils response.
39 | ///
40 | [Fact]
41 | public void DataReadCoilsResponse()
42 | {
43 | var col = new DiscreteCollection(false, true, false, true, false, true, false, false, false, false);
44 | AbstractModbusMessageWithData message = new ReadCoilsInputsResponse(Modbus.ReadCoils, 11, 1, col);
45 | Assert.Equal(col.Count, message.Data.Count);
46 | Assert.Equal(col.NetworkBytes, message.Data.NetworkBytes);
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/src/ModbusRx.UnitTests/Message/ReadCoilsInputsRequestFixture.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Chris Pulman. All rights reserved.
2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3 |
4 | using System;
5 | using ModbusRx.Message;
6 | using Xunit;
7 |
8 | namespace ModbusRx.UnitTests.Message;
9 |
10 | ///
11 | /// ReadCoilsInputsRequestFixture.
12 | ///
13 | public class ReadCoilsInputsRequestFixture
14 | {
15 | ///
16 | /// Creates the read coils request.
17 | ///
18 | [Fact]
19 | public void CreateReadCoilsRequest()
20 | {
21 | var request = new ReadCoilsInputsRequest(Modbus.ReadCoils, 5, 1, 10);
22 | Assert.Equal(Modbus.ReadCoils, request.FunctionCode);
23 | Assert.Equal(5, request.SlaveAddress);
24 | Assert.Equal(1, request.StartAddress);
25 | Assert.Equal(10, request.NumberOfPoints);
26 | }
27 |
28 | ///
29 | /// Creates the read inputs request.
30 | ///
31 | [Fact]
32 | public void CreateReadInputsRequest()
33 | {
34 | var request = new ReadCoilsInputsRequest(Modbus.ReadInputs, 5, 1, 10);
35 | Assert.Equal(Modbus.ReadInputs, request.FunctionCode);
36 | Assert.Equal(5, request.SlaveAddress);
37 | Assert.Equal(1, request.StartAddress);
38 | Assert.Equal(10, request.NumberOfPoints);
39 | }
40 |
41 | ///
42 | /// Creates the read coils inputs request too much data.
43 | ///
44 | [Fact]
45 | public void CreateReadCoilsInputsRequestTooMuchData() =>
46 | Assert.Throws(() => new ReadCoilsInputsRequest(Modbus.ReadCoils, 1, 2, Modbus.MaximumDiscreteRequestResponseSize + 1));
47 |
48 | ///
49 | /// Creates the maximum size of the read coils inputs request.
50 | ///
51 | [Fact]
52 | public void CreateReadCoilsInputsRequestMaxSize()
53 | {
54 | var response = new ReadCoilsInputsRequest(Modbus.ReadCoils, 1, 2, Modbus.MaximumDiscreteRequestResponseSize);
55 | Assert.Equal(Modbus.MaximumDiscreteRequestResponseSize, response.NumberOfPoints);
56 | }
57 |
58 | ///
59 | /// Converts to string_readcoilsrequest.
60 | ///
61 | [Fact]
62 | public void ToString_ReadCoilsRequest()
63 | {
64 | var request = new ReadCoilsInputsRequest(Modbus.ReadCoils, 5, 1, 10);
65 |
66 | Assert.Equal("Read 10 coils starting at address 1.", request.ToString());
67 | }
68 |
69 | ///
70 | /// Converts to string_readinputsrequest.
71 | ///
72 | [Fact]
73 | public void ToString_ReadInputsRequest()
74 | {
75 | var request = new ReadCoilsInputsRequest(Modbus.ReadInputs, 5, 1, 10);
76 |
77 | Assert.Equal("Read 10 inputs starting at address 1.", request.ToString());
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/src/ModbusRx.UnitTests/Message/ReadCoilsInputsResponseFixture.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Chris Pulman. All rights reserved.
2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3 |
4 | using ModbusRx.Data;
5 | using ModbusRx.Message;
6 | using Xunit;
7 |
8 | namespace ModbusRx.UnitTests.Message;
9 |
10 | ///
11 | /// ReadCoilsInputsResponseFixture.
12 | ///
13 | public class ReadCoilsInputsResponseFixture
14 | {
15 | ///
16 | /// Creates the read coils response.
17 | ///
18 | [Fact]
19 | public void CreateReadCoilsResponse()
20 | {
21 | var response = new ReadCoilsInputsResponse(Modbus.ReadCoils, 5, 2, new DiscreteCollection(true, true, true, true, true, true, false, false, true, true, false));
22 | Assert.Equal(Modbus.ReadCoils, response.FunctionCode);
23 | Assert.Equal(5, response.SlaveAddress);
24 | Assert.Equal(2, response.ByteCount);
25 | var col = new DiscreteCollection(true, true, true, true, true, true, false, false, true, true, false);
26 | Assert.Equal(col.NetworkBytes, response.Data.NetworkBytes);
27 | }
28 |
29 | ///
30 | /// Creates the read inputs response.
31 | ///
32 | [Fact]
33 | public void CreateReadInputsResponse()
34 | {
35 | var response = new ReadCoilsInputsResponse(Modbus.ReadInputs, 5, 2, new DiscreteCollection(true, true, true, true, true, true, false, false, true, true, false));
36 | Assert.Equal(Modbus.ReadInputs, response.FunctionCode);
37 | Assert.Equal(5, response.SlaveAddress);
38 | Assert.Equal(2, response.ByteCount);
39 | var col = new DiscreteCollection(true, true, true, true, true, true, false, false, true, true, false);
40 | Assert.Equal(col.NetworkBytes, response.Data.NetworkBytes);
41 | }
42 |
43 | ///
44 | /// Converts to string_coils.
45 | ///
46 | [Fact]
47 | public void ToString_Coils()
48 | {
49 | var response = new ReadCoilsInputsResponse(Modbus.ReadCoils, 5, 2, new DiscreteCollection(true, true, true, true, true, true, false, false, true, true, false));
50 |
51 | Assert.Equal("Read 11 coils - {1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0}.", response.ToString());
52 | }
53 |
54 | ///
55 | /// Converts to string_inputs.
56 | ///
57 | [Fact]
58 | public void ToString_Inputs()
59 | {
60 | var response = new ReadCoilsInputsResponse(Modbus.ReadInputs, 5, 2, new DiscreteCollection(true, true, true, true, true, true, false, false, true, true, false));
61 |
62 | Assert.Equal("Read 11 inputs - {1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0}.", response.ToString());
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/src/ModbusRx.UnitTests/Message/ReadHoldingInputRegistersRequestFixture.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Chris Pulman. All rights reserved.
2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3 |
4 | using System;
5 | using ModbusRx.Message;
6 | using Xunit;
7 |
8 | namespace ModbusRx.UnitTests.Message;
9 |
10 | ///
11 | /// ReadHoldingInputRegistersRequestFixture.
12 | ///
13 | public class ReadHoldingInputRegistersRequestFixture
14 | {
15 | ///
16 | /// Creates the read holding registers request.
17 | ///
18 | [Fact]
19 | public void CreateReadHoldingRegistersRequest()
20 | {
21 | var request = new ReadHoldingInputRegistersRequest(Modbus.ReadHoldingRegisters, 5, 1, 10);
22 |
23 | Assert.Equal(Modbus.ReadHoldingRegisters, request.FunctionCode);
24 | Assert.Equal(5, request.SlaveAddress);
25 | Assert.Equal(1, request.StartAddress);
26 | Assert.Equal(10, request.NumberOfPoints);
27 | }
28 |
29 | ///
30 | /// Creates the read input registers request.
31 | ///
32 | [Fact]
33 | public void CreateReadInputRegistersRequest()
34 | {
35 | var request = new ReadHoldingInputRegistersRequest(Modbus.ReadInputRegisters, 5, 1, 10);
36 |
37 | Assert.Equal(Modbus.ReadInputRegisters, request.FunctionCode);
38 | Assert.Equal(5, request.SlaveAddress);
39 | Assert.Equal(1, request.StartAddress);
40 | Assert.Equal(10, request.NumberOfPoints);
41 | }
42 |
43 | ///
44 | /// Creates the read holding input registers request too much data.
45 | ///
46 | [Fact]
47 | public void CreateReadHoldingInputRegistersRequestTooMuchData() =>
48 | Assert.Throws(() =>
49 | new ReadHoldingInputRegistersRequest(Modbus.ReadHoldingRegisters, 1, 2, Modbus.MaximumRegisterRequestResponseSize + 1));
50 |
51 | ///
52 | /// Creates the maximum size of the read holding input registers request.
53 | ///
54 | [Fact]
55 | public void CreateReadHoldingInputRegistersRequestMaxSize()
56 | {
57 | var response = new ReadHoldingInputRegistersRequest(Modbus.ReadHoldingRegisters, 1, 2, Modbus.MaximumRegisterRequestResponseSize);
58 |
59 | Assert.Equal(Modbus.MaximumRegisterRequestResponseSize, response.NumberOfPoints);
60 | }
61 |
62 | ///
63 | /// Converts to string_readholdingregistersrequest.
64 | ///
65 | [Fact]
66 | public void ToString_ReadHoldingRegistersRequest()
67 | {
68 | var request = new ReadHoldingInputRegistersRequest(Modbus.ReadHoldingRegisters, 5, 1, 10);
69 |
70 | Assert.Equal("Read 10 holding registers starting at address 1.", request.ToString());
71 | }
72 |
73 | ///
74 | /// Converts to string_readinputregistersrequest.
75 | ///
76 | [Fact]
77 | public void ToString_ReadInputRegistersRequest()
78 | {
79 | var request = new ReadHoldingInputRegistersRequest(Modbus.ReadInputRegisters, 5, 1, 10);
80 |
81 | Assert.Equal("Read 10 input registers starting at address 1.", request.ToString());
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/src/ModbusRx.UnitTests/Message/ReadHoldingInputRegistersResponseFixture.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Chris Pulman. All rights reserved.
2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3 |
4 | using System;
5 | using ModbusRx.Data;
6 | using ModbusRx.Message;
7 | using Xunit;
8 |
9 | namespace ModbusRx.UnitTests.Message;
10 |
11 | ///
12 | /// ReadHoldingInputRegistersResponseFixture.
13 | ///
14 | public class ReadHoldingInputRegistersResponseFixture
15 | {
16 | ///
17 | /// Reads the holding input registers response null data.
18 | ///
19 | [Fact]
20 | public void ReadHoldingInputRegistersResponse_NullData() => Assert.Throws(() => new ReadHoldingInputRegistersResponse(0, 0, null!));
21 |
22 | ///
23 | /// Reads the holding registers response.
24 | ///
25 | [Fact]
26 | public void ReadHoldingRegistersResponse()
27 | {
28 | var response = new ReadHoldingInputRegistersResponse(Modbus.ReadHoldingRegisters, 5, new RegisterCollection(1, 2));
29 | Assert.Equal(Modbus.ReadHoldingRegisters, response.FunctionCode);
30 | Assert.Equal(5, response.SlaveAddress);
31 | Assert.Equal(4, response.ByteCount);
32 | var col = new RegisterCollection(1, 2);
33 | Assert.Equal(col.NetworkBytes, response.Data.NetworkBytes);
34 | }
35 |
36 | ///
37 | /// Converts to string_readholdingregistersresponse.
38 | ///
39 | [Fact]
40 | public void ToString_ReadHoldingRegistersResponse()
41 | {
42 | var response = new ReadHoldingInputRegistersResponse(Modbus.ReadHoldingRegisters, 1, new RegisterCollection(1));
43 | Assert.Equal("Read 1 holding registers.", response.ToString());
44 | }
45 |
46 | ///
47 | /// Reads the input registers response.
48 | ///
49 | [Fact]
50 | public void ReadInputRegistersResponse()
51 | {
52 | var response = new ReadHoldingInputRegistersResponse(Modbus.ReadInputRegisters, 5, new RegisterCollection(1, 2));
53 | Assert.Equal(Modbus.ReadInputRegisters, response.FunctionCode);
54 | Assert.Equal(5, response.SlaveAddress);
55 | Assert.Equal(4, response.ByteCount);
56 | var col = new RegisterCollection(1, 2);
57 | Assert.Equal(col.NetworkBytes, response.Data.NetworkBytes);
58 | }
59 |
60 | ///
61 | /// Converts to string_readinputregistersresponse.
62 | ///
63 | [Fact]
64 | public void ToString_ReadInputRegistersResponse()
65 | {
66 | var response = new ReadHoldingInputRegistersResponse(Modbus.ReadInputRegisters, 1, new RegisterCollection(1));
67 | Assert.Equal("Read 1 input registers.", response.ToString());
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/src/ModbusRx.UnitTests/Message/ReadWriteMultipleRegistersRequestFixture.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Chris Pulman. All rights reserved.
2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3 |
4 | using ModbusRx.Data;
5 | using ModbusRx.Message;
6 | using Xunit;
7 |
8 | namespace ModbusRx.UnitTests.Message;
9 |
10 | ///
11 | /// ReadWriteMultipleRegistersRequestFixture.
12 | ///
13 | public class ReadWriteMultipleRegistersRequestFixture
14 | {
15 | ///
16 | /// Reads the write multiple registers request.
17 | ///
18 | [Fact]
19 | public void ReadWriteMultipleRegistersRequest()
20 | {
21 | var writeCollection = new RegisterCollection(255, 255, 255);
22 | var request = new ReadWriteMultipleRegistersRequest(5, 3, 6, 14, writeCollection);
23 | Assert.Equal(Modbus.ReadWriteMultipleRegisters, request.FunctionCode);
24 | Assert.Equal(5, request.SlaveAddress);
25 |
26 | // test read
27 | Assert.NotNull(request.ReadRequest);
28 | Assert.Equal(request.SlaveAddress, request.ReadRequest!.SlaveAddress);
29 | Assert.Equal(3, request.ReadRequest.StartAddress);
30 | Assert.Equal(6, request.ReadRequest.NumberOfPoints);
31 |
32 | // test write
33 | Assert.NotNull(request.WriteRequest);
34 | Assert.Equal(request.SlaveAddress, request.WriteRequest!.SlaveAddress);
35 | Assert.Equal(14, request.WriteRequest.StartAddress);
36 | Assert.Equal(writeCollection.NetworkBytes, request.WriteRequest.Data.NetworkBytes);
37 | }
38 |
39 | ///
40 | /// Protocols the data unit.
41 | ///
42 | [Fact]
43 | public void ProtocolDataUnit()
44 | {
45 | var writeCollection = new RegisterCollection(255, 255, 255);
46 | var request = new ReadWriteMultipleRegistersRequest(5, 3, 6, 14, writeCollection);
47 | byte[] pdu =
48 | {
49 | 0x17, 0x00, 0x03, 0x00, 0x06, 0x00, 0x0e, 0x00, 0x03, 0x06, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff,
50 | };
51 | Assert.Equal(pdu, request.ProtocolDataUnit);
52 | }
53 |
54 | ///
55 | /// Converts to string_readwritemultipleregistersrequest.
56 | ///
57 | [Fact]
58 | public void ToString_ReadWriteMultipleRegistersRequest()
59 | {
60 | var writeCollection = new RegisterCollection(255, 255, 255);
61 | var request = new ReadWriteMultipleRegistersRequest(5, 3, 6, 14, writeCollection);
62 |
63 | Assert.Equal(
64 | "Write 3 holding registers starting at address 14, and read 6 registers starting at address 3.",
65 | request.ToString());
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/src/ModbusRx.UnitTests/Message/ReturnQueryDataRequestResponseFixture.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Chris Pulman. All rights reserved.
2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3 |
4 | using ModbusRx.Data;
5 | using ModbusRx.Message;
6 | using Xunit;
7 |
8 | namespace ModbusRx.UnitTests.Message;
9 |
10 | ///
11 | /// ReturnQueryDataRequestResponseFixture.
12 | ///
13 | public class ReturnQueryDataRequestResponseFixture
14 | {
15 | ///
16 | /// Returns the query data request response.
17 | ///
18 | [Fact]
19 | public void ReturnQueryDataRequestResponse()
20 | {
21 | var data = new RegisterCollection(1, 2, 3, 4);
22 | var request = new DiagnosticsRequestResponse(Modbus.DiagnosticsReturnQueryData, 5, data);
23 | Assert.Equal(Modbus.Diagnostics, request.FunctionCode);
24 | Assert.Equal(Modbus.DiagnosticsReturnQueryData, request.SubFunctionCode);
25 | Assert.Equal(5, request.SlaveAddress);
26 | Assert.Equal(data.NetworkBytes, request.Data.NetworkBytes);
27 | }
28 |
29 | ///
30 | /// Protocols the data unit.
31 | ///
32 | [Fact]
33 | public void ProtocolDataUnit()
34 | {
35 | var data = new RegisterCollection(1, 2, 3, 4);
36 | var request = new DiagnosticsRequestResponse(Modbus.DiagnosticsReturnQueryData, 5, data);
37 | Assert.Equal(new byte[] { 8, 0, 0, 0, 1, 0, 2, 0, 3, 0, 4 }, request.ProtocolDataUnit);
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/src/ModbusRx.UnitTests/Message/SlaveExceptionResponseFixture.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Chris Pulman. All rights reserved.
2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3 |
4 | using ModbusRx.Message;
5 | using Xunit;
6 |
7 | namespace ModbusRx.UnitTests.Message;
8 |
9 | ///
10 | /// SlaveExceptionResponseFixture.
11 | ///
12 | public class SlaveExceptionResponseFixture
13 | {
14 | ///
15 | /// Creates the slave exception response.
16 | ///
17 | [Fact]
18 | public void CreateSlaveExceptionResponse()
19 | {
20 | var response = new SlaveExceptionResponse(11, Modbus.ReadCoils + Modbus.ExceptionOffset, 2);
21 | Assert.Equal(11, response.SlaveAddress);
22 | Assert.Equal(Modbus.ReadCoils + Modbus.ExceptionOffset, response.FunctionCode);
23 | Assert.Equal(2, response.SlaveExceptionCode);
24 | }
25 |
26 | ///
27 | /// Slaves the exception response pdu.
28 | ///
29 | [Fact]
30 | public void SlaveExceptionResponsePDU()
31 | {
32 | var response = new SlaveExceptionResponse(11, Modbus.ReadCoils + Modbus.ExceptionOffset, 2);
33 | Assert.Equal(new byte[] { response.FunctionCode, response.SlaveExceptionCode }, response.ProtocolDataUnit);
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/src/ModbusRx.UnitTests/Message/WriteMultipleCoilsRequestFixture.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Chris Pulman. All rights reserved.
2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3 |
4 | using System;
5 | using ModbusRx.Data;
6 | using ModbusRx.Message;
7 | using Xunit;
8 |
9 | namespace ModbusRx.UnitTests.Message;
10 |
11 | ///
12 | /// WriteMultipleCoilsRequestFixture.
13 | ///
14 | public class WriteMultipleCoilsRequestFixture
15 | {
16 | ///
17 | /// Creates the write multiple coils request.
18 | ///
19 | [Fact]
20 | public void CreateWriteMultipleCoilsRequest()
21 | {
22 | var col = new DiscreteCollection(true, false, true, false, true, true, true, false, false);
23 | var request = new WriteMultipleCoilsRequest(34, 45, col);
24 | Assert.Equal(Modbus.WriteMultipleCoils, request.FunctionCode);
25 | Assert.Equal(34, request.SlaveAddress);
26 | Assert.Equal(45, request.StartAddress);
27 | Assert.Equal(9, request.NumberOfPoints);
28 | Assert.Equal(2, request.ByteCount);
29 | Assert.Equal(col.NetworkBytes, request.Data.NetworkBytes);
30 | }
31 |
32 | ///
33 | /// Creates the write multiple coils request too much data.
34 | ///
35 | [Fact]
36 | public void CreateWriteMultipleCoilsRequestTooMuchData() =>
37 | Assert.Throws(() =>
38 | new WriteMultipleCoilsRequest(1, 2, MessageUtility.CreateDefaultCollection(true, Modbus.MaximumDiscreteRequestResponseSize + 1)));
39 |
40 | ///
41 | /// Creates the maximum size of the write multiple coils request.
42 | ///
43 | [Fact]
44 | public void CreateWriteMultipleCoilsRequestMaxSize()
45 | {
46 | var request = new WriteMultipleCoilsRequest(1, 2, MessageUtility.CreateDefaultCollection(true, Modbus.MaximumDiscreteRequestResponseSize));
47 |
48 | Assert.Equal(Modbus.MaximumDiscreteRequestResponseSize, request.Data.Count);
49 | }
50 |
51 | ///
52 | /// Converts to string_writemultiplecoilsrequest.
53 | ///
54 | [Fact]
55 | public void ToString_WriteMultipleCoilsRequest()
56 | {
57 | var col = new DiscreteCollection(true, false, true, false, true, true, true, false, false);
58 | var request = new WriteMultipleCoilsRequest(34, 45, col);
59 |
60 | Assert.Equal("Write 9 coils starting at address 45.", request.ToString());
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/src/ModbusRx.UnitTests/Message/WriteMultipleCoilsResponseFixture.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Chris Pulman. All rights reserved.
2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3 |
4 | using System;
5 | using ModbusRx.Message;
6 | using Xunit;
7 |
8 | namespace ModbusRx.UnitTests.Message;
9 |
10 | ///
11 | /// WriteMultipleCoilsResponseFixture.
12 | ///
13 | public class WriteMultipleCoilsResponseFixture
14 | {
15 | ///
16 | /// Creates the write multiple coils response.
17 | ///
18 | [Fact]
19 | public void CreateWriteMultipleCoilsResponse()
20 | {
21 | var response = new WriteMultipleCoilsResponse(17, 19, 45);
22 | Assert.Equal(Modbus.WriteMultipleCoils, response.FunctionCode);
23 | Assert.Equal(17, response.SlaveAddress);
24 | Assert.Equal(19, response.StartAddress);
25 | Assert.Equal(45, response.NumberOfPoints);
26 | }
27 |
28 | ///
29 | /// Creates the write multiple coils response too much data.
30 | ///
31 | [Fact]
32 | public void CreateWriteMultipleCoilsResponseTooMuchData() => Assert.Throws(() => new WriteMultipleCoilsResponse(1, 2, Modbus.MaximumDiscreteRequestResponseSize + 1));
33 |
34 | ///
35 | /// Creates the maximum size of the write multiple coils response.
36 | ///
37 | [Fact]
38 | public void CreateWriteMultipleCoilsResponseMaxSize()
39 | {
40 | var response = new WriteMultipleCoilsResponse(1, 2, Modbus.MaximumDiscreteRequestResponseSize);
41 | Assert.Equal(Modbus.MaximumDiscreteRequestResponseSize, response.NumberOfPoints);
42 | }
43 |
44 | ///
45 | /// Converts to string_test.
46 | ///
47 | [Fact]
48 | public void ToString_Test()
49 | {
50 | var response = new WriteMultipleCoilsResponse(1, 2, 3);
51 |
52 | Assert.Equal("Wrote 3 coils starting at address 2.", response.ToString());
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/src/ModbusRx.UnitTests/Message/WriteMultipleRegistersRequestFixture.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Chris Pulman. All rights reserved.
2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3 |
4 | using System;
5 | using ModbusRx.Data;
6 | using ModbusRx.Message;
7 | using Xunit;
8 |
9 | namespace ModbusRx.UnitTests.Message;
10 |
11 | ///
12 | /// WriteMultipleRegistersRequestFixture.
13 | ///
14 | public class WriteMultipleRegistersRequestFixture
15 | {
16 | ///
17 | /// Creates the write multiple registers request fixture.
18 | ///
19 | [Fact]
20 | public void CreateWriteMultipleRegistersRequestFixture()
21 | {
22 | var col = new RegisterCollection(10, 20, 30, 40, 50);
23 | var request = new WriteMultipleRegistersRequest(11, 34, col);
24 |
25 | Assert.Equal(Modbus.WriteMultipleRegisters, request.FunctionCode);
26 | Assert.Equal(11, request.SlaveAddress);
27 | Assert.Equal(34, request.StartAddress);
28 | Assert.Equal(10, request.ByteCount);
29 | Assert.Equal(col.NetworkBytes, request.Data.NetworkBytes);
30 | }
31 |
32 | ///
33 | /// Creates the write multiple registers request too much data.
34 | ///
35 | [Fact]
36 | public void CreateWriteMultipleRegistersRequestTooMuchData() =>
37 | Assert.Throws(() =>
38 | new WriteMultipleRegistersRequest(1, 2, MessageUtility.CreateDefaultCollection(3, Modbus.MaximumRegisterRequestResponseSize + 1)));
39 |
40 | ///
41 | /// Creates the maximum size of the write multiple registers request.
42 | ///
43 | [Fact]
44 | public void CreateWriteMultipleRegistersRequestMaxSize()
45 | {
46 | var request = new WriteMultipleRegistersRequest(1, 2, MessageUtility.CreateDefaultCollection(3, Modbus.MaximumRegisterRequestResponseSize));
47 |
48 | Assert.Equal(Modbus.MaximumRegisterRequestResponseSize, request.NumberOfPoints);
49 | }
50 |
51 | ///
52 | /// Converts to string_writemultipleregistersrequest.
53 | ///
54 | [Fact]
55 | public void ToString_WriteMultipleRegistersRequest()
56 | {
57 | var col = new RegisterCollection(10, 20, 30, 40, 50);
58 | var request = new WriteMultipleRegistersRequest(11, 34, col);
59 |
60 | Assert.Equal("Write 5 holding registers starting at address 34.", request.ToString());
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/src/ModbusRx.UnitTests/Message/WriteMultipleRegistersResponseFixture.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Chris Pulman. All rights reserved.
2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3 |
4 | using System;
5 | using ModbusRx.Message;
6 | using Xunit;
7 |
8 | namespace ModbusRx.UnitTests.Message;
9 |
10 | ///
11 | /// WriteMultipleRegistersResponseFixture.
12 | ///
13 | public class WriteMultipleRegistersResponseFixture
14 | {
15 | ///
16 | /// Creates the write multiple registers response.
17 | ///
18 | [Fact]
19 | public void CreateWriteMultipleRegistersResponse()
20 | {
21 | var response = new WriteMultipleRegistersResponse(12, 39, 2);
22 | Assert.Equal(Modbus.WriteMultipleRegisters, response.FunctionCode);
23 | Assert.Equal(12, response.SlaveAddress);
24 | Assert.Equal(39, response.StartAddress);
25 | Assert.Equal(2, response.NumberOfPoints);
26 | }
27 |
28 | ///
29 | /// Creates the write multiple registers response too much data.
30 | ///
31 | [Fact]
32 | public void CreateWriteMultipleRegistersResponseTooMuchData() => Assert.Throws(() => new WriteMultipleRegistersResponse(1, 2, Modbus.MaximumRegisterRequestResponseSize + 1));
33 |
34 | ///
35 | /// Creates the maximum size of the write multiple registers response.
36 | ///
37 | [Fact]
38 | public void CreateWriteMultipleRegistersResponseMaxSize()
39 | {
40 | var response = new WriteMultipleRegistersResponse(1, 2, Modbus.MaximumRegisterRequestResponseSize);
41 | Assert.Equal(Modbus.MaximumRegisterRequestResponseSize, response.NumberOfPoints);
42 | }
43 |
44 | ///
45 | /// Converts to string_test.
46 | ///
47 | [Fact]
48 | public void ToString_Test()
49 | {
50 | var response = new WriteMultipleRegistersResponse(1, 2, 3);
51 |
52 | Assert.Equal("Wrote 3 holding registers starting at address 2.", response.ToString());
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/src/ModbusRx.UnitTests/Message/WriteSingleCoilRequestResponseFixture.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Chris Pulman. All rights reserved.
2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3 |
4 | using ModbusRx.Message;
5 | using Xunit;
6 |
7 | namespace ModbusRx.UnitTests.Message;
8 |
9 | ///
10 | /// WriteSingleCoilRequestResponseFixture.
11 | ///
12 | public class WriteSingleCoilRequestResponseFixture
13 | {
14 | ///
15 | /// Creates new writesinglecoilrequestresponse.
16 | ///
17 | [Fact]
18 | public void NewWriteSingleCoilRequestResponse()
19 | {
20 | var request = new WriteSingleCoilRequestResponse(11, 5, true);
21 | Assert.Equal(11, request.SlaveAddress);
22 | Assert.Equal(5, request.StartAddress);
23 | Assert.Single(request.Data);
24 | Assert.Equal(Modbus.CoilOn, request.Data[0]);
25 | }
26 |
27 | ///
28 | /// Converts to string_true.
29 | ///
30 | [Fact]
31 | public void ToString_True()
32 | {
33 | var request = new WriteSingleCoilRequestResponse(11, 5, true);
34 |
35 | Assert.Equal("Write single coil 1 at address 5.", request.ToString());
36 | }
37 |
38 | ///
39 | /// Converts to string_false.
40 | ///
41 | [Fact]
42 | public void ToString_False()
43 | {
44 | var request = new WriteSingleCoilRequestResponse(11, 5, false);
45 |
46 | Assert.Equal("Write single coil 0 at address 5.", request.ToString());
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/src/ModbusRx.UnitTests/Message/WriteSingleRegisterRequestResponseFixture.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Chris Pulman. All rights reserved.
2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3 |
4 | using ModbusRx.Message;
5 | using Xunit;
6 |
7 | namespace ModbusRx.UnitTests.Message;
8 |
9 | ///
10 | /// WriteSingleRegisterRequestResponseFixture.
11 | ///
12 | public class WriteSingleRegisterRequestResponseFixture
13 | {
14 | ///
15 | /// Creates new writesingleregisterrequestresponse.
16 | ///
17 | [Fact]
18 | public void NewWriteSingleRegisterRequestResponse()
19 | {
20 | var message = new WriteSingleRegisterRequestResponse(12, 5, 1200);
21 | Assert.Equal(12, message.SlaveAddress);
22 | Assert.Equal(5, message.StartAddress);
23 | Assert.Single(message.Data);
24 | Assert.Equal(1200, message.Data[0]);
25 | }
26 |
27 | ///
28 | /// Converts to stringoverride.
29 | ///
30 | [Fact]
31 | public void ToStringOverride()
32 | {
33 | var message = new WriteSingleRegisterRequestResponse(12, 5, 1200);
34 | Assert.Equal("Write single holding register 1200 at address 5.", message.ToString());
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/src/ModbusRx.UnitTests/ModbusRx.UnitTests.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | false
5 | net48;net6.0;
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/src/ModbusRx.UnitTests/SlaveExceptionFixture.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Chris Pulman. All rights reserved.
2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3 |
4 | using System;
5 | using System.IO;
6 | using ModbusRx.Message;
7 | using Xunit;
8 |
9 | namespace ModbusRx.UnitTests;
10 |
11 | ///
12 | /// SlaveExceptionFixture.
13 | ///
14 | public class SlaveExceptionFixture
15 | {
16 | ///
17 | /// Empties the constructor.
18 | ///
19 | [Fact]
20 | public void EmptyConstructor()
21 | {
22 | var e = new SlaveException();
23 | Assert.Equal($"Exception of type '{typeof(SlaveException).FullName}' was thrown.", e.Message);
24 | Assert.Equal(0, e.SlaveAddress);
25 | Assert.Equal(0, e.FunctionCode);
26 | Assert.Equal(0, e.SlaveExceptionCode);
27 | Assert.Null(e.InnerException);
28 | }
29 |
30 | ///
31 | /// Constructors the with message.
32 | ///
33 | [Fact]
34 | public void ConstructorWithMessage()
35 | {
36 | var e = new SlaveException("Hello World");
37 | Assert.Equal("Hello World", e.Message);
38 | Assert.Equal(0, e.SlaveAddress);
39 | Assert.Equal(0, e.FunctionCode);
40 | Assert.Equal(0, e.SlaveExceptionCode);
41 | Assert.Null(e.InnerException);
42 | }
43 |
44 | ///
45 | /// Constructors the with message and inner exception.
46 | ///
47 | [Fact]
48 | public void ConstructorWithMessageAndInnerException()
49 | {
50 | var inner = new IOException("Bar");
51 | var e = new SlaveException("Foo", inner);
52 | Assert.Equal("Foo", e.Message);
53 | Assert.Same(inner, e.InnerException);
54 | Assert.Equal(0, e.SlaveAddress);
55 | Assert.Equal(0, e.FunctionCode);
56 | Assert.Equal(0, e.SlaveExceptionCode);
57 | }
58 |
59 | ///
60 | /// Constructors the with slave exception response.
61 | ///
62 | [Fact]
63 | public void ConstructorWithSlaveExceptionResponse()
64 | {
65 | var response = new SlaveExceptionResponse(12, Modbus.ReadCoils, 1);
66 | var e = new SlaveException(response);
67 |
68 | Assert.Equal(12, e.SlaveAddress);
69 | Assert.Equal(Modbus.ReadCoils, e.FunctionCode);
70 | Assert.Equal(1, e.SlaveExceptionCode);
71 | Assert.Null(e.InnerException);
72 |
73 | Assert.Equal(
74 | $@"Exception of type '{typeof(SlaveException).FullName}' was thrown.{Environment.NewLine}Function Code: {response.FunctionCode}{Environment.NewLine}Exception Code: {response.SlaveExceptionCode} - {Resources.IllegalFunction}",
75 | e.Message);
76 | }
77 |
78 | ///
79 | /// Constructors the with custom message and slave exception response.
80 | ///
81 | [Fact]
82 | public void ConstructorWithCustomMessageAndSlaveExceptionResponse()
83 | {
84 | var response = new SlaveExceptionResponse(12, Modbus.ReadCoils, 2);
85 | var customMessage = "custom message";
86 | var e = new SlaveException(customMessage, response);
87 |
88 | Assert.Equal(12, e.SlaveAddress);
89 | Assert.Equal(Modbus.ReadCoils, e.FunctionCode);
90 | Assert.Equal(2, e.SlaveExceptionCode);
91 | Assert.Null(e.InnerException);
92 |
93 | Assert.Equal(
94 | $@"{customMessage}{Environment.NewLine}Function Code: {response.FunctionCode}{Environment.NewLine}Exception Code: {response.SlaveExceptionCode} - {Resources.IllegalDataAddress}",
95 | e.Message);
96 | }
97 | }
98 |
--------------------------------------------------------------------------------
/src/ModbusRx.UnitTests/Utility/CollectionUtilityFixture.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Chris Pulman. All rights reserved.
2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3 |
4 | using System;
5 | using System.Collections.Generic;
6 | using System.Collections.ObjectModel;
7 | using System.Linq;
8 | using ModbusRx.Data;
9 | using ModbusRx.UnitTests.Message;
10 | using ModbusRx.Unme.Common;
11 | using Xunit;
12 |
13 | namespace ModbusRx.UnitTests.Utility;
14 |
15 | ///
16 | /// CollectionUtilityFixture.
17 | ///
18 | public class CollectionUtilityFixture
19 | {
20 | ///
21 | /// Slices the middle.
22 | ///
23 | [Fact]
24 | public void SliceMiddle()
25 | {
26 | byte[] test = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
27 | Assert.Equal(new byte[] { 3, 4, 5, 6, 7 }, test.Slice(2, 5).ToArray());
28 | }
29 |
30 | ///
31 | /// Slices the beginning.
32 | ///
33 | [Fact]
34 | public void SliceBeginning()
35 | {
36 | byte[] test = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
37 | Assert.Equal(new byte[] { 1, 2 }, test.Slice(0, 2).ToArray());
38 | }
39 |
40 | ///
41 | /// Slices the end.
42 | ///
43 | [Fact]
44 | public void SliceEnd()
45 | {
46 | byte[] test = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
47 | Assert.Equal(new byte[] { 9, 10 }, test.Slice(8, 2).ToArray());
48 | }
49 |
50 | ///
51 | /// Slices the collection.
52 | ///
53 | [Fact]
54 | public void SliceCollection()
55 | {
56 | var col = new Collection(new bool[] { true, false, false, false, true, true });
57 | Assert.Equal(new bool[] { false, false, true }, col.Slice(2, 3).ToArray());
58 | }
59 |
60 | ///
61 | /// Slices the read only collection.
62 | ///
63 | [Fact]
64 | public void SliceReadOnlyCollection()
65 | {
66 | var col = new ReadOnlyCollection(new bool[] { true, false, false, false, true, true });
67 | Assert.Equal(new bool[] { false, false, true }, col.Slice(2, 3).ToArray());
68 | }
69 |
70 | ///
71 | /// Slices the null i collection.
72 | ///
73 | [Fact]
74 | public void SliceNullICollection()
75 | {
76 | ICollection col = null!;
77 | Assert.Throws(() => col.Slice(1, 1).ToArray());
78 | }
79 |
80 | ///
81 | /// Slices the null array.
82 | ///
83 | [Fact]
84 | public void SliceNullArray()
85 | {
86 | bool[] array = null!;
87 | Assert.Throws(() => array.Slice(1, 1).ToArray());
88 | }
89 |
90 | ///
91 | /// Creates the default size of the collection negative.
92 | ///
93 | [Fact]
94 | public void CreateDefaultCollectionNegativeSize() =>
95 | Assert.Throws(() => MessageUtility.CreateDefaultCollection(0, -1));
96 |
97 | ///
98 | /// Creates the default collection.
99 | ///
100 | [Fact]
101 | public void CreateDefaultCollection()
102 | {
103 | var col = MessageUtility.CreateDefaultCollection(3, 5);
104 | Assert.Equal(5, col.Count);
105 | Assert.Equal(new ushort[] { 3, 3, 3, 3, 3 }, col.ToArray());
106 | }
107 | }
108 |
--------------------------------------------------------------------------------
/src/ModbusRx.UnitTests/Utility/DiscriminatedUnionFixture.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Chris Pulman. All rights reserved.
2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3 |
4 | using System;
5 | using ModbusRx.Utility;
6 | using Xunit;
7 |
8 | namespace ModbusRx.UnitTests.Utility;
9 |
10 | ///
11 | /// DiscriminatedUnionFixture.
12 | ///
13 | public class DiscriminatedUnionFixture
14 | {
15 | ///
16 | /// Discriminateds the union create a.
17 | ///
18 | [Fact]
19 | public void DiscriminatedUnion_CreateA()
20 | {
21 | var du = DiscriminatedUnion.CreateA("foo");
22 | Assert.Equal(DiscriminatedUnionOption.A, du.Option);
23 | Assert.Equal("foo", du.A);
24 | }
25 |
26 | ///
27 | /// Discriminateds the union create b.
28 | ///
29 | [Fact]
30 | public void DiscriminatedUnion_CreateB()
31 | {
32 | var du = DiscriminatedUnion.CreateB("foo");
33 | Assert.Equal(DiscriminatedUnionOption.B, du.Option);
34 | Assert.Equal("foo", du.B);
35 | }
36 |
37 | ///
38 | /// Discriminateds the union allow nulls.
39 | ///
40 | [Fact]
41 | public void DiscriminatedUnion_AllowNulls()
42 | {
43 | var du = DiscriminatedUnion