9 Commits
v0.4.2 ... main

Author SHA1 Message Date
83339e2ea0 Bump to v0.5.0
All checks were successful
Branch Build / build-test-deploy (push) Successful in 2m35s
Release Build / build-test-deploy (push) Successful in 2m34s
2026-01-12 19:00:20 +01:00
283eee556f Updated to .NET 10
All checks were successful
Branch Build / build-test-deploy (push) Successful in 1m49s
2026-01-12 18:55:29 +01:00
f7978c6277 Migrating to VS 2026 2026-01-12 18:31:30 +01:00
56b83f2d33 Migrated CI from gitlab to gitea 2026-01-12 18:30:35 +01:00
793a088c5b Update editorconfig 2025-08-08 17:52:06 +02:00
b216304482 Added missing snapshot tests 2025-08-07 16:42:54 +02:00
e87649ff43 Added basic information for docs 2025-08-07 16:21:10 +02:00
11295ea247 Added automatic documentation generation on Release 2025-08-07 16:20:33 +02:00
799a014b15 Moving structure as preparation for docs 2025-08-06 21:08:55 +02:00
134 changed files with 1416 additions and 1077 deletions

View File

@@ -91,6 +91,7 @@ dotnet_naming_style.prefix_underscore.required_prefix = _
[*.cs]
csharp_preferred_modifier_order = public, private, protected, internal, static, extern, new, virtual, abstract, sealed, override, readonly, unsafe, volatile, async:suggestion
csharp_style_prefer_primary_constructors = false
# Only use "var" when it's obvious what the variable type is
csharp_style_var_for_built_in_types = false:warning
@@ -157,3 +158,6 @@ csharp_space_between_square_brackets = false
[*.{xml,csproj,targets,props,json,yml}]
indent_size = 2
indent_style = space
[*.{json,yml}]
end_of_line = lf

View File

@@ -0,0 +1,60 @@
name: Branch Build
on:
push:
branches:
- '**'
env:
TZ: 'Europe/Berlin'
LANG: 'de'
CONFIGURATION: 'Debug'
GITEA_SERVER_URL: ${{ gitea.server_url }}
jobs:
build-test-deploy:
runs-on: ubuntu
steps:
- name: Checkout repository code
uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Setup dotnet
uses: actions/setup-dotnet@v5
with:
dotnet-version: 10.x
cache: false
- name: Restore dependencies
run: |
set -ex
dotnet restore -v q
echo "CI_SERVER_HOST=${GITEA_SERVER_URL#https://}" >> "$GITEA_ENV"
- name: Setup tools
run: |
set -ex
dotnet tool install dotnet-reportgenerator-globaltool --tool-path /dotnet-tools
- name: Build solution
shell: bash
run: |
set -ex
shopt -s globstar
mkdir /artifacts
dotnet build -c ${CONFIGURATION} --no-restore --nologo
mv ./**/*.nupkg /artifacts/ || true
mv ./**/*.snupkg /artifacts/ || true
- name: Test solution
run: |
set -ex
dotnet test -c ${CONFIGURATION} --no-build --nologo /p:CoverletOutputFormat=Cobertura
/dotnet-tools/reportgenerator "-reports:${{ gitea.workspace }}/**/coverage.cobertura.xml" "-targetdir:/reports" "-reportType:TextSummary"
cat /reports/Summary.txt
- name: Publish packages
run: |
set -ex
dotnet nuget push -k "${{ secrets.BAGET_APIKEY }}" -s https://nuget.am-wd.de/v3/index.json --skip-duplicate /artifacts/*.nupkg

View File

@@ -0,0 +1,78 @@
name: Release Build
on:
push:
tags:
- 'v*'
env:
TZ: 'Europe/Berlin'
LANG: 'de'
CONFIGURATION: 'Release'
GITEA_SERVER_URL: ${{ gitea.server_url }}
jobs:
build-test-deploy:
runs-on: ubuntu
steps:
- name: Checkout repository code
uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Setup dotnet
uses: actions/setup-dotnet@v5
with:
dotnet-version: 10.x
cache: false
- name: Restore dependencies
run: |
set -ex
dotnet restore -v q
echo "CI_SERVER_HOST=${GITEA_SERVER_URL#https://}" >> "$GITEA_ENV"
- name: Setup tools
run: |
set -ex
dotnet tool install dotnet-reportgenerator-globaltool --tool-path /dotnet-tools
dotnet tool install docfx --tool-path /dotnet-tools
- name: Build solution
shell: bash
run: |
set -ex
shopt -s globstar
mkdir /artifacts
dotnet build -c ${CONFIGURATION} --no-restore --nologo
mv ./**/*.nupkg /artifacts/ || true
mv ./**/*.snupkg /artifacts/ || true
- name: Test solution
run: |
set -ex
dotnet test -c ${CONFIGURATION} --no-build --nologo /p:CoverletOutputFormat=Cobertura
/dotnet-tools/reportgenerator "-reports:${{ gitea.workspace }}/**/coverage.cobertura.xml" "-targetdir:/reports" "-reportType:TextSummary"
- name: Publish packages
run: |
set -ex
dotnet nuget push -k "${{ secrets.NUGET_APIKEY }}" -s https://api.nuget.org/v3/index.json --skip-duplicate /artifacts/*.nupkg
- name: Publish documentation
env:
DOCFX_SOURCE_REPOSITORY_URL: 'https://github.com/AM-WD/AMWD.Protocols.Modbus'
run: |
set -ex
/dotnet-tools/docfx metadata docs/docfx.json
/dotnet-tools/docfx build docs/docfx.json
tar -C "${{ gitea.workspace }}/docs/_site" -czf "/artifacts/docs.tar.gz" .
curl -sSL --no-progress-meter --user "${{ secrets.DOCS_DEPLOY_USER }}:${{ secrets.DOCS_DEPLOY_PASS }}" -F docs=modbus -F dump=@/artifacts/docs.tar.gz "${{ vars.DOCS_DEPLOY_URL }}"
- name: Upload artifacts
uses: actions/upload-artifact@v3
with:
name: artifacts
path: |
/artifacts/*
/reports/Summary.txt

3
.gitignore vendored
View File

@@ -2,6 +2,9 @@
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
docs/api
docs/_site
# User-specific files
*.suo
*.user

View File

@@ -1,134 +0,0 @@
image: mcr.microsoft.com/dotnet/sdk:8.0
variables:
TZ: "Europe/Berlin"
LANG: "de"
stages:
- build
- test
- deploy
build-debug:
stage: build
tags:
- docker
- lnx
- 64bit
rules:
- if: $CI_COMMIT_TAG == null
script:
- shopt -s globstar
- mkdir ./artifacts
- dotnet restore --no-cache --force
- dotnet build -c Debug --nologo --no-restore --no-incremental
- mv ./**/*.nupkg ./artifacts/
- mv ./**/*.snupkg ./artifacts/
artifacts:
paths:
- artifacts/*.nupkg
- artifacts/*.snupkg
expire_in: 1 days
test-debug:
stage: test
dependencies:
- build-debug
tags:
- docker
- lnx
- 64bit
rules:
- if: $CI_COMMIT_TAG == null
coverage: /Branch coverage[\s\S].+%/
before_script:
- dotnet tool install dotnet-reportgenerator-globaltool --tool-path /dotnet-tools
script:
- dotnet test -c Debug --nologo /p:CoverletOutputFormat=Cobertura
- /dotnet-tools/reportgenerator "-reports:${CI_PROJECT_DIR}/**/coverage.cobertura.xml" "-targetdir:/reports" -reportType:TextSummary
after_script:
- cat /reports/Summary.txt
artifacts:
when: always
reports:
coverage_report:
coverage_format: cobertura
path: ./**/coverage.cobertura.xml
deploy-debug:
stage: deploy
dependencies:
- build-debug
- test-debug
tags:
- docker
- lnx
- 64bit
rules:
- if: $CI_COMMIT_TAG == null
script:
- dotnet nuget push -k $BAGET_APIKEY -s https://nuget.am-wd.de/v3/index.json --skip-duplicate artifacts/*.nupkg
build-release:
stage: build
tags:
- docker
- lnx
- amd64
rules:
- if: $CI_COMMIT_TAG != null
script:
- shopt -s globstar
- mkdir ./artifacts
- dotnet restore --no-cache --force
- dotnet build -c Release --nologo --no-restore --no-incremental
- mv ./**/*.nupkg ./artifacts/
- mv ./**/*.snupkg ./artifacts/
artifacts:
paths:
- artifacts/*.nupkg
- artifacts/*.snupkg
expire_in: 7 days
test-release:
stage: test
dependencies:
- build-release
tags:
- docker
- lnx
- amd64
rules:
- if: $CI_COMMIT_TAG != null
coverage: /Branch coverage[\s\S].+%/
before_script:
- dotnet tool install dotnet-reportgenerator-globaltool --tool-path /dotnet-tools
script:
- dotnet test -c Release --nologo /p:CoverletOutputFormat=Cobertura
- /dotnet-tools/reportgenerator "-reports:${CI_PROJECT_DIR}/**/coverage.cobertura.xml" "-targetdir:/reports" -reportType:TextSummary
after_script:
- cat /reports/Summary.txt
artifacts:
when: always
reports:
coverage_report:
coverage_format: cobertura
path: ./**/coverage.cobertura.xml
deploy-release:
stage: deploy
dependencies:
- build-release
- test-release
tags:
- docker
- lnx
- 64bit
rules:
- if: $CI_COMMIT_TAG != null
script:
- dotnet nuget push -k $NUGET_APIKEY -s https://api.nuget.org/v3/index.json --skip-duplicate artifacts/*.nupkg

View File

@@ -1,30 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>netstandard2.0;net6.0;net8.0</TargetFrameworks>
<PackageId>AMWD.Protocols.Modbus.Tcp</PackageId>
<AssemblyName>amwd-modbus-tcp</AssemblyName>
<RootNamespace>AMWD.Protocols.Modbus.Tcp</RootNamespace>
<Product>Modbus TCP Protocol</Product>
<Description>Implementation of the Modbus protocol communicating via TCP.</Description>
<PackageTags>Modbus Protocol Network TCP LAN</PackageTags>
</PropertyGroup>
<ItemGroup>
<Compile Include="$(SolutionDir)/AMWD.Protocols.Modbus.Common/Extensions/ArrayExtensions.cs" Link="Extensions/ArrayExtensions.cs" />
<Compile Include="$(SolutionDir)/AMWD.Protocols.Modbus.Common/Extensions/ReaderWriterLockSlimExtensions.cs" Link="Extensions/ReaderWriterLockSlimExtensions.cs" />
<Compile Include="$(SolutionDir)/AMWD.Protocols.Modbus.Common/Utils/AsyncQueue.cs" Link="Utils/AsyncQueue.cs" />
<Compile Include="$(SolutionDir)/AMWD.Protocols.Modbus.Common/Utils/RequestQueueItem.cs" Link="Utils/RequestQueueItem.cs" />
</ItemGroup>
<ItemGroup>
<None Include="README.md" Pack="true" PackagePath="/" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="$(SolutionDir)\AMWD.Protocols.Modbus.Common\AMWD.Protocols.Modbus.Common.csproj" />
</ItemGroup>
</Project>

View File

@@ -1,32 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<IsPackable>false</IsPackable>
<IsTestProject>true</IsTestProject>
<CollectCoverage>true</CollectCoverage>
<CoverletOutputFormat>Cobertura</CoverletOutputFormat>
<GeneratePackageOnBuild>false</GeneratePackageOnBuild>
<GenerateDocumentationFile>false</GenerateDocumentationFile>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="coverlet.msbuild" Version="6.0.4">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.12.0" />
<PackageReference Include="Moq" Version="4.20.72" />
<PackageReference Include="MSTest.TestAdapter" Version="3.7.2" />
<PackageReference Include="MSTest.TestFramework" Version="3.7.2" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="$(SolutionDir)\AMWD.Protocols.Modbus.Common\AMWD.Protocols.Modbus.Common.csproj" />
<ProjectReference Include="$(SolutionDir)\AMWD.Protocols.Modbus.Serial\AMWD.Protocols.Modbus.Serial.csproj" />
<ProjectReference Include="$(SolutionDir)\AMWD.Protocols.Modbus.Tcp\AMWD.Protocols.Modbus.Tcp.csproj" />
</ItemGroup>
</Project>

View File

@@ -1,5 +0,0 @@
global using System;
global using System.Linq;
global using AMWD.Protocols.Modbus.Common;
global using AMWD.Protocols.Modbus.Common.Contracts;
global using Microsoft.VisualStudio.TestTools.UnitTesting;

View File

@@ -1,84 +0,0 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.8.34525.116
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AMWD.Protocols.Modbus.Common", "AMWD.Protocols.Modbus.Common\AMWD.Protocols.Modbus.Common.csproj", "{2B7689D8-9E56-4DEB-B40E-F70DB4A6F250}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{0C43172F-63F3-455A-A5FC-CAE7492A969B}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "docs", "docs", "{A5A9AEA2-3AFF-4536-9FF9-34663DA4D0AD}"
ProjectSection(SolutionItems) = preProject
CHANGELOG.md = CHANGELOG.md
LICENSE.txt = LICENSE.txt
package-icon.png = package-icon.png
README.md = README.md
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "config", "config", "{2ED08B2B-1F72-4E1E-9586-1DC6BEFD7BA7}"
ProjectSection(SolutionItems) = preProject
.editorconfig = .editorconfig
.gitignore = .gitignore
CodeMaid.config = CodeMaid.config
nuget.config = nuget.config
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "build", "build", "{C8065AE3-BA87-49AC-8100-C85D6DF7E436}"
ProjectSection(SolutionItems) = preProject
.gitlab-ci.yml = .gitlab-ci.yml
Directory.Build.props = Directory.Build.props
EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AMWD.Protocols.Modbus.Tests", "AMWD.Protocols.Modbus.Tests\AMWD.Protocols.Modbus.Tests.csproj", "{146070C4-E922-4F5A-AD6F-9A899186E26E}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AMWD.Protocols.Modbus.Tcp", "AMWD.Protocols.Modbus.Tcp\AMWD.Protocols.Modbus.Tcp.csproj", "{8C888A84-CD09-4087-B5DA-67708ABBABA2}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AMWD.Protocols.Modbus.Serial", "AMWD.Protocols.Modbus.Serial\AMWD.Protocols.Modbus.Serial.csproj", "{D966826F-EE6C-4BC0-9185-C2A9A50FD586}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CliClient", "CliClient\CliClient.csproj", "{B0E53462-B0ED-4685-8AA5-948DC160EE27}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CliProxy", "CliProxy\CliProxy.csproj", "{AC922E80-E9B6-493D-B1D1-752527E883ED}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{2B7689D8-9E56-4DEB-B40E-F70DB4A6F250}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2B7689D8-9E56-4DEB-B40E-F70DB4A6F250}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2B7689D8-9E56-4DEB-B40E-F70DB4A6F250}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2B7689D8-9E56-4DEB-B40E-F70DB4A6F250}.Release|Any CPU.Build.0 = Release|Any CPU
{146070C4-E922-4F5A-AD6F-9A899186E26E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{146070C4-E922-4F5A-AD6F-9A899186E26E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{146070C4-E922-4F5A-AD6F-9A899186E26E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{146070C4-E922-4F5A-AD6F-9A899186E26E}.Release|Any CPU.Build.0 = Release|Any CPU
{8C888A84-CD09-4087-B5DA-67708ABBABA2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{8C888A84-CD09-4087-B5DA-67708ABBABA2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8C888A84-CD09-4087-B5DA-67708ABBABA2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8C888A84-CD09-4087-B5DA-67708ABBABA2}.Release|Any CPU.Build.0 = Release|Any CPU
{D966826F-EE6C-4BC0-9185-C2A9A50FD586}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D966826F-EE6C-4BC0-9185-C2A9A50FD586}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D966826F-EE6C-4BC0-9185-C2A9A50FD586}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D966826F-EE6C-4BC0-9185-C2A9A50FD586}.Release|Any CPU.Build.0 = Release|Any CPU
{B0E53462-B0ED-4685-8AA5-948DC160EE27}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B0E53462-B0ED-4685-8AA5-948DC160EE27}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B0E53462-B0ED-4685-8AA5-948DC160EE27}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B0E53462-B0ED-4685-8AA5-948DC160EE27}.Release|Any CPU.Build.0 = Release|Any CPU
{AC922E80-E9B6-493D-B1D1-752527E883ED}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{AC922E80-E9B6-493D-B1D1-752527E883ED}.Debug|Any CPU.Build.0 = Debug|Any CPU
{AC922E80-E9B6-493D-B1D1-752527E883ED}.Release|Any CPU.ActiveCfg = Release|Any CPU
{AC922E80-E9B6-493D-B1D1-752527E883ED}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{A5A9AEA2-3AFF-4536-9FF9-34663DA4D0AD} = {0C43172F-63F3-455A-A5FC-CAE7492A969B}
{2ED08B2B-1F72-4E1E-9586-1DC6BEFD7BA7} = {0C43172F-63F3-455A-A5FC-CAE7492A969B}
{C8065AE3-BA87-49AC-8100-C85D6DF7E436} = {0C43172F-63F3-455A-A5FC-CAE7492A969B}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {E4FD8EF0-3594-4994-BE80-5FADA5EE17B4}
EndGlobalSection
EndGlobal

View File

@@ -0,0 +1,38 @@
<Solution>
<Folder Name="/Solution Items/" />
<Folder Name="/Solution Items/build/">
<File Path="Directory.Build.props" />
</Folder>
<Folder Name="/Solution Items/build/workflows/">
<File Path=".gitea/workflows/branch-build.yml" />
<File Path=".gitea/workflows/release-build.yml" />
</Folder>
<Folder Name="/Solution Items/config/">
<File Path=".editorconfig" />
<File Path=".gitignore" />
<File Path="CodeMaid.config" />
<File Path="nuget.config" />
</Folder>
<Folder Name="/Solution Items/docs/">
<File Path="CHANGELOG.md" />
<File Path="LICENSE.txt" />
<File Path="package-icon.png" />
<File Path="README.md" />
</Folder>
<Folder Name="/src/">
<Project Path="src/AMWD.Protocols.Modbus.Common/AMWD.Protocols.Modbus.Common.csproj" />
<Project Path="src/AMWD.Protocols.Modbus.Serial/AMWD.Protocols.Modbus.Serial.csproj" />
<Project Path="src/AMWD.Protocols.Modbus.Tcp/AMWD.Protocols.Modbus.Tcp.csproj" />
<File Path="src/Directory.Build.props" />
</Folder>
<Folder Name="/test/">
<File Path="test/MSTestSettings.cs" />
<Project Path="test/AMWD.Protocols.Modbus.Tests/AMWD.Protocols.Modbus.Tests.csproj" />
<File Path="test/Directory.Build.props" />
</Folder>
<Folder Name="/tool/">
<Project Path="tool/CliClient/CliClient.csproj" />
<Project Path="tool/CliProxy/CliProxy.csproj" />
<File Path="tool/Directory.Build.props" />
</Folder>
</Solution>

View File

@@ -7,7 +7,22 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]
_nothing changed yet_
_no changes yet_
## [v0.5.0] (2026-01-12)
### Added
- New automatic documentation generation using docfx.
- Additional articles for the documentation.
### Changed
- Reorganized folder structure to allow documentation generation.
- Migrated main repository from GitLab to Gitea.
- Migrated to VS 2026.
- Updated UnitTests and Tools to .NET 10.
## [v0.4.2] (2025-02-07)
@@ -95,7 +110,9 @@ So this tag is only here for documentation purposes of the NuGet Gallery.
[Unreleased]: https://github.com/AM-WD/AMWD.Protocols.Modbus/compare/v0.4.2...HEAD
[Unreleased]: https://github.com/AM-WD/AMWD.Protocols.Modbus/compare/v0.5.0...HEAD
[v0.5.0]: https://github.com/AM-WD/AMWD.Protocols.Modbus/compare/v0.4.2...v0.5.0
[v0.4.2]: https://github.com/AM-WD/AMWD.Protocols.Modbus/compare/v0.4.1...v0.4.2
[v0.4.1]: https://github.com/AM-WD/AMWD.Protocols.Modbus/compare/v0.4.0...v0.4.1
[v0.4.0]: https://github.com/AM-WD/AMWD.Protocols.Modbus/compare/v0.3.2...v0.4.0

View File

@@ -1,34 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<AssemblyName>modbus-client</AssemblyName>
<RootNamespace>AMWD.Protocols.Modbus.CliClient</RootNamespace>
<Product>Modbus CLI client</Product>
<Description>Small CLI client for Modbus communication.</Description>
<IsPackable>false</IsPackable>
<SignAssembly>false</SignAssembly>
<GeneratePackageOnBuild>false</GeneratePackageOnBuild>
<InvariantGlobalization>true</InvariantGlobalization>
</PropertyGroup>
<ItemGroup>
<None Remove="$(SolutionDir)/package-icon.png" />
<None Remove="$(SolutionDir)/LICENSE.txt" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="System.IO.Ports" Version="8.0.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="$(SolutionDir)\AMWD.Protocols.Modbus.Serial\AMWD.Protocols.Modbus.Serial.csproj" />
<ProjectReference Include="$(SolutionDir)\AMWD.Protocols.Modbus.Tcp\AMWD.Protocols.Modbus.Tcp.csproj" />
</ItemGroup>
</Project>

View File

@@ -1,34 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<AssemblyName>modbus-proxy</AssemblyName>
<RootNamespace>AMWD.Protocols.Modbus.CliProxy</RootNamespace>
<Product>Modbus CLI proxy</Product>
<Description>Small CLI proxy to forward messages.</Description>
<IsPackable>false</IsPackable>
<SignAssembly>false</SignAssembly>
<GeneratePackageOnBuild>false</GeneratePackageOnBuild>
<InvariantGlobalization>true</InvariantGlobalization>
</PropertyGroup>
<ItemGroup>
<None Remove="$(SolutionDir)/package-icon.png" />
<None Remove="$(SolutionDir)/LICENSE.txt" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="System.IO.Ports" Version="8.0.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="$(SolutionDir)\AMWD.Protocols.Modbus.Serial\AMWD.Protocols.Modbus.Serial.csproj" />
<ProjectReference Include="$(SolutionDir)\AMWD.Protocols.Modbus.Tcp\AMWD.Protocols.Modbus.Tcp.csproj" />
</ItemGroup>
</Project>

View File

@@ -1,62 +1,20 @@
<Project>
<PropertyGroup>
<LangVersion>12.0</LangVersion>
<LangVersion>14.0</LangVersion>
<NrtRevisionFormat>{semvertag:main}{!:-dev}</NrtRevisionFormat>
<AppendTargetFrameworkToOutputPath>true</AppendTargetFrameworkToOutputPath>
<CopyRefAssembliesToPublishDirectory>false</CopyRefAssembliesToPublishDirectory>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<RepositoryType>git</RepositoryType>
<RepositoryUrl>https://github.com/AM-WD/AMWD.Protocols.Modbus.git</RepositoryUrl>
<PublishRepositoryUrl>true</PublishRepositoryUrl>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<IncludeSymbols>true</IncludeSymbols>
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
<EmbedUntrackedSources>false</EmbedUntrackedSources>
<PackageIcon>package-icon.png</PackageIcon>
<PackageReadmeFile>README.md</PackageReadmeFile>
<PackageLicenseFile>LICENSE.txt</PackageLicenseFile>
<Title>Modbus Protocol for .NET</Title>
<Company>AM.WD</Company>
<Authors>Andreas Müller</Authors>
<Copyright>© {copyright:2018-} AM.WD</Copyright>
<SignAssembly>true</SignAssembly>
<AssemblyOriginatorKeyFile>$(SolutionDir)/AMWD.Protocols.Modbus.snk</AssemblyOriginatorKeyFile>
<PublicKey>0024000004800000940000000602000000240000525341310004000001000100adcc4f9f5bb3ac73cb30661f6f35772b8f90a74412925764a960af06ef125bdcec05ed1d139503d5203fb72aa3fa74bab58e82ac2a6cd4b650f8cbf7086a71bc2dfc67e95b8d26d776d60856acf3121f831529b1a4dee91b34ac84f95f71a1165b7783edb591929ba2a684100c92bbed8859c7266fb507f6f55bb6f7fcac80b4</PublicKey>
<MoqPublicKey>0024000004800000940000000602000000240000525341310004000001000100c547cac37abd99c8db225ef2f6c8a3602f3b3606cc9891605d02baa56104f4cfc0734aa39b93bf7852f7d9266654753cc297e7d2edfe0bac1cdcf9f717241550e0a7b191195b7667bb4f64bcb8e2121380fd1d9d46ad2d92d2d15605093924cceaf74c4861eff62abf69b9291ed0a340e113be11e6a7d3113e92484cf7045cc7</MoqPublicKey>
</PropertyGroup>
<PropertyGroup Condition="'$(GITLAB_CI)' == 'true'">
<ContinuousIntegrationBuild>true</ContinuousIntegrationBuild>
</PropertyGroup>
<ItemGroup Condition="'$(SignAssembly)' != 'true'">
<InternalsVisibleTo Include="AMWD.Protocols.Modbus.Tests" />
<InternalsVisibleTo Include="DynamicProxyGenAssembly2" />
</ItemGroup>
<ItemGroup Condition="'$(SignAssembly)' == 'true'">
<InternalsVisibleTo Include="AMWD.Protocols.Modbus.Tests" PublicKey="0024000004800000940000000602000000240000525341310004000001000100adcc4f9f5bb3ac73cb30661f6f35772b8f90a74412925764a960af06ef125bdcec05ed1d139503d5203fb72aa3fa74bab58e82ac2a6cd4b650f8cbf7086a71bc2dfc67e95b8d26d776d60856acf3121f831529b1a4dee91b34ac84f95f71a1165b7783edb591929ba2a684100c92bbed8859c7266fb507f6f55bb6f7fcac80b4" />
<InternalsVisibleTo Include="DynamicProxyGenAssembly2" PublicKey="0024000004800000940000000602000000240000525341310004000001000100c547cac37abd99c8db225ef2f6c8a3602f3b3606cc9891605d02baa56104f4cfc0734aa39b93bf7852f7d9266654753cc297e7d2edfe0bac1cdcf9f717241550e0a7b191195b7667bb4f64bcb8e2121380fd1d9d46ad2d92d2d15605093924cceaf74c4861eff62abf69b9291ed0a340e113be11e6a7d3113e92484cf7045cc7" />
</ItemGroup>
<ItemGroup Condition="'$(GITLAB_CI)' == 'true'">
<SourceLinkGitLabHost Include="$(CI_SERVER_HOST)" Version="$(CI_SERVER_VERSION)" />
<PackageReference Include="Microsoft.SourceLink.GitLab" Version="8.0.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>
<ItemGroup>
<None Include="$(SolutionDir)/package-icon.png" Pack="true" PackagePath="/" />
<None Include="$(SolutionDir)/LICENSE.txt" Pack="true" PackagePath="/" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="AMWD.NetRevisionTask" Version="1.2.1">
<PackageReference Include="AMWD.NetRevisionTask" Version="1.4.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>

View File

@@ -3,7 +3,6 @@
Here you can find a basic implementation of the Modbus protocol.
![NuGet Version](https://shields.io/nuget/v/AMWD.Protocols.Modbus.Common?style=flat&logo=nuget)
![Test Coverage](https://git.am-wd.de/am-wd/amwd.protocols.modbus/badges/main/coverage.svg?style=flat)
## Overview
@@ -38,14 +37,12 @@ It uses a specific TCP connection implementation and plugs all things from the C
---
Published under [MIT License] (see [choose a license])
[![Buy me a Coffee](https://shields.io/badge/PayPal-Buy_me_a_Coffee-yellow?style=flat&logo=paypal)](https://link.am-wd.de/donate)
[![built with Codeium](https://codeium.com/badges/main)](https://link.am-wd.de/codeium)
[see here]: https://github.com/andreasAMmueller/Modbus
[Common]: AMWD.Protocols.Modbus.Common/README.md
[Serial]: AMWD.Protocols.Modbus.Serial/README.md
[TCP]: AMWD.Protocols.Modbus.Tcp/README.md
[Common]: src/AMWD.Protocols.Modbus.Common/README.md
[Serial]: src/AMWD.Protocols.Modbus.Serial/README.md
[TCP]: src/AMWD.Protocols.Modbus.Tcp/README.md
[MIT License]: LICENSE.txt
[choose a license]: https://choosealicense.com/licenses/mit/

View File

@@ -0,0 +1,106 @@
# Getting Started
To begin, you need at least the [Common] package.
In this package you'll find everything you need to implement you own client as the package contains the protocol implementations (`TCP`, `RTU` and `ASCII`).
The [`ModbusClientBase`](~/api/AMWD.Protocols.Modbus.Common.Contracts.ModbusClientBase.yml) is the place, where most of the magic happens.
In this base client you have all known (and implemented) methods to request a device.
The Protocol implementations are the other magic place to be, as there the request will be converted into bits and bytes, before they get transfered.
## Using a TCP client
To use a TCP Modbus client, you need the [Common] package and the [TCP] package installed.
```cs
using AMWD.Protocols.Modbus.Common;
using AMWD.Protocols.Modbus.Common.Contracts;
using AMWD.Protocols.Modbus.Common.Protocols;
using AMWD.Protocols.Modbus.Tcp;
namespace ConsoleApp;
internal class Program
{
string hostname = "modbus-device.internal";
int port = 502;
byte unitId = 5;
ushort startAddress = 19000;
ushort count = 2;
using var client = new ModbusTcpClient(hostname, port);
await client.ConnectAsync(CancellationToken.None);
var holdingRegisters = await client.ReadHoldingRegistersAsync(unitId, startAddress, count);
float voltage = holdingRegisters.GetSingle();
Console.WriteLine($"The voltage of the device #{unitId} between L1 and N is {voltage:N2}V.");
}
```
This will automatically create a TCP client using the TCP protocol.
If you want to change the protocol sent over TCP, you can specify it:
```cs
// [...] other code
using var client = new ModbusTcpClient(hostname, port)
{
Protocol = new RtuProtocol()
};
// [...] other code
```
## Using a Serial client
To use a Serial Modbus client, you need the [Common] package and the [Serial] package installed.
```cs
using AMWD.Protocols.Modbus.Common;
using AMWD.Protocols.Modbus.Common.Contracts;
using AMWD.Protocols.Modbus.Common.Protocols;
using AMWD.Protocols.Modbus.Serial;
namespace ConsoleApp;
internal class Program
{
string serialPort = "/dev/ttyUSB0";
byte unitId = 5;
ushort startAddress = 19000;
ushort count = 2;
using var client = new ModbusSerialClient(serialPort);
await client.ConnectAsync(CancellationToken.None);
var holdingRegisters = await client.ReadHoldingRegistersAsync(unitId, startAddress, count);
float voltage = holdingRegisters.GetSingle();
Console.WriteLine($"The voltage of the device #{unitId} between L1 and N is {voltage:N2}V.");
}
```
This will automatically create a Serial client using the RTU protocol.
If you want to change the protocol sent over serial line, you can specify it:
```cs
// [...] other code
using var client = new ModbusSerialClient(serialPort)
{
Protocol = new AsciiProtocol()
};
// [...] other code
```
[Common]: https://www.nuget.org/packages/AMWD.Protocols.Modbus.Common
[Serial]: https://www.nuget.org/packages/AMWD.Protocols.Modbus.Serial
[TCP]: https://www.nuget.org/packages/AMWD.Protocols.Modbus.Tcp

View File

@@ -0,0 +1,20 @@
# Introduction
During my training, I came into contact with the Modbus protocol.
The implementation I developed at that time was very cumbersome and rigid.
There were huge inheritance hierarchies and the design was very confusing.
In 2018, I wanted to do better and completely redesigned the library.
After changing companies, this library could be integrated and tested under real-world conditions.
This quickly led to new challenges and some specific requirements were implemented.
This was the first time that both TCP and the RTU protocol were fully implemented.
However, the structure of the library also revealed problems and was too rigid for the requirements.
Therefore, in 2024, there was a new development from scratch, which now exists and has already been tested by some eager people THANK YOU SO MUCH!
The focus is, of course, on the development of the protocol and the clients. However, a server implementation (TCP/RTU) is also available.
For detailed changes of the current development, see the [CHANGELOG].
[CHANGELOG]: https://github.com/AM-WD/AMWD.Protocols.Modbus/blob/main/CHANGELOG.md

8
docs/articles/toc.yml Normal file
View File

@@ -0,0 +1,8 @@
- name: Introduction
href: introduction.md
- name: Getting Started
href: getting-started.md
- name: GitHub
href: https://github.com/AM-WD/AMWD.Protocols.Modbus
- name: NuGet
href: https://www.nuget.org/packages?q=AMWD.Protocols.Modbus

63
docs/docfx.json Normal file
View File

@@ -0,0 +1,63 @@
{
"$schema": "https://raw.githubusercontent.com/dotnet/docfx/main/schemas/docfx.schema.json",
"metadata": [
{
"src": [
{
"src": "../",
"files": [
"src/AMWD.Protocols.Modbus.Common/bin/Release/netstandard2.0/amwd-modbus-common.dll",
"src/AMWD.Protocols.Modbus.Serial/bin/Release/netstandard2.0/amwd-modbus-serial.dll",
"src/AMWD.Protocols.Modbus.Tcp/bin/Release/netstandard2.0/amwd-modbus-tcp.dll"
]
}
],
"dest": "api",
"outputFormat": "apiPage"
}
],
"build": {
"content": [
{
"files": [ "**/*.{md,yml}" ],
"exclude": [ "_site/**", "obj/**" ]
}
],
"resource": [
{
"files": [ "images/**" ],
"exclude": [ "_site/**", "obj/**" ]
}
],
"output": "_site",
"template": [ "default", "modern", "templates/amwd" ],
"postProcessors": ["ExtractSearchIndex"],
"globalMetadata": {
"_appName": "Protocol for .NET",
"_appTitle": "Modbus Protocol for .NET",
"_appFooter": "<span>&copy; AM.WD &mdash; Docs generated using <a href=\"https://dotnet.github.io/docfx\" target=\"_blank\">docfx</a>.</span>",
"_appLogoPath": "images/logo.svg",
"_appFaviconPath": "images/favicon.ico",
"_disableBreadcrumb": true,
"_disableContribution": true,
"_enableSearch": true,
"_enableNewTab": true,
"pdf": false
},
"markdownEngineName": "markdig",
"markdownEngineProperties": {
"alerts": {
"TODO": "alert alert-secondary"
}
},
"sitemap": {
"baseUrl": "https://docs.am-wd.de/modbus",
"priority": 0.5,
"changefreq": "weekly"
},
"noLangKeyword": false,
"keepFileLink": false,
"cleanupCacheHistory": false,
"disableGitFeatures": true
}
}

BIN
docs/images/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 162 KiB

168
docs/images/logo.svg Normal file
View File

@@ -0,0 +1,168 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="103.59954"
height="35"
viewBox="0 0 172.52591 58.286041"
version="1.1"
id="svg17631"
inkscape:version="1.1.2 (0a00cf5339, 2022-02-04)"
sodipodi:docname="Logo of Modbus.svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview17633"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:document-units="mm"
showgrid="false"
inkscape:zoom="0.64052329"
inkscape:cx="352.0559"
inkscape:cy="108.50503"
inkscape:window-width="1850"
inkscape:window-height="1136"
inkscape:window-x="70"
inkscape:window-y="27"
inkscape:window-maximized="1"
inkscape:current-layer="layer1" />
<defs
id="defs17628">
<clipPath
id="clip1">
<path
d="M 54,12.761719 H 76 V 34 H 54 Z m 0,0"
id="path619" />
</clipPath>
<clipPath
id="clip2">
<path
d="M 71,73 H 93 V 94.441406 H 71 Z m 0,0"
id="path622" />
</clipPath>
<clipPath
id="clip3">
<path
d="M 32.160156,35 H 54 V 57 H 32.160156 Z m 0,0"
id="path625" />
</clipPath>
<clipPath
id="clip4">
<path
d="m 247,46 h 26.92578 V 67 H 247 Z m 0,0"
id="path628" />
</clipPath>
</defs>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(-11.970621,-119.59261)">
<path
style="fill:#f5911c;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.713609"
d="m 61.396335,149.27146 c 0,11.04421 -8.9452,20.00055 -19.983825,20.00055 -11.035839,0 -19.983816,-8.95634 -19.983816,-20.00055 0,-11.04698 8.947977,-20.00054 19.983816,-20.00054 11.038625,0 19.983825,8.95356 19.983825,20.00054"
id="path944" />
<path
style="fill:#fdbf0c;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.713609"
d="m 64.409645,132.37902 c 0.14496,4.13949 -3.09137,7.61274 -7.22807,7.7577 -4.13669,0.14503 -7.60717,-3.09416 -7.75212,-7.23365 -0.14217,-4.13947 3.09416,-7.61275 7.22807,-7.7577 4.1367,-0.14504 7.60718,3.09415 7.75212,7.23365"
id="path946" />
<path
style="fill:#fdbf0c;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.713609"
d="m 33.038765,164.56666 c 0.144956,4.13949 -3.091374,7.61274 -7.22807,7.7577 -4.136699,0.14503 -7.607177,-3.09416 -7.752129,-7.23365 -0.144956,-4.13949 3.091375,-7.61275 7.228071,-7.7577 4.136698,-0.14504 7.607177,3.09415 7.752128,7.23365"
id="path948" />
<g
clip-path="url(#clip1)"
clip-rule="nonzero"
id="g952"
transform="matrix(0.7136082,0,0,0.7136082,-10.979154,110.48574)">
<path
style="fill:#fdbf0c;fill-opacity:1;fill-rule:nonzero;stroke:none"
d="m 69.574219,13.992188 c 5.121093,2.726562 7.066406,9.089843 4.339843,14.214843 -2.722656,5.125 -9.078124,7.070313 -14.199218,4.34375 -5.121094,-2.722656 -7.066406,-9.085937 -4.34375,-14.210937 2.722656,-5.125 9.082031,-7.074219 14.203125,-4.347656"
id="path950" />
</g>
<g
clip-path="url(#clip2)"
clip-rule="nonzero"
id="g956"
transform="matrix(0.7136082,0,0,0.7136082,-10.979154,110.48574)">
<path
style="fill:#fdbf0c;fill-opacity:1;fill-rule:nonzero;stroke:none"
d="m 86.625,74.648438 c 5.121094,2.722656 7.0625,9.085937 4.339844,14.214843 -2.722656,5.121094 -9.078125,7.070313 -14.199219,4.34375 -5.121094,-2.722656 -7.066406,-9.089843 -4.34375,-14.214843 2.722656,-5.125 9.082031,-7.070313 14.203125,-4.34375"
id="path954" />
</g>
<g
clip-path="url(#clip3)"
clip-rule="nonzero"
id="g960"
transform="matrix(0.7136082,0,0,0.7136082,-10.979154,110.48574)">
<path
style="fill:#fdbf0c;fill-opacity:1;fill-rule:nonzero;stroke:none"
d="m 37.097656,36.910156 c 4.917969,-3.074218 11.398438,-1.578125 14.472656,3.34375 3.074219,4.925782 1.578126,11.40625 -3.34375,14.484375 -4.917968,3.074219 -11.394531,1.578125 -14.46875,-3.34375 -3.074218,-4.921875 -1.578124,-11.40625 3.339844,-14.484375"
id="path958" />
</g>
<path
style="fill:#fdbf0c;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.713609"
d="m 59.032505,147.92229 c 3.5095,-2.19377 8.13401,-1.12616 10.3278,2.38613 2.191,3.51229 1.12338,8.13959 -2.38613,10.33618 -3.5095,2.19377 -8.13123,1.12617 -10.32501,-2.38613 -2.19379,-3.51229 -1.12617,-8.13959 2.38334,-10.33618"
id="path962" />
<path
style="fill:#008cc7;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.713609"
d="m 86.963565,148.26516 c -0.76378,0.61047 -1.06761,1.52758 -1.22094,2.44188 -0.15333,0.91711 -0.30662,2.14084 0,2.60077 0.30385,0.45436 1.83143,0.61046 1.83143,0.61046 h 3.5095 c 0,0 1.68087,0 2.44467,-0.45993 0.76377,-0.45715 0.91429,-1.37703 1.21814,-2.5952 0.30941,-1.22373 0.15333,-1.98751 0,-2.44467 -0.1505,-0.45993 -1.67809,-0.61047 -1.67809,-0.61047 h -3.96667 c 0,0 -1.37424,-0.15333 -2.13804,0.45716 z m 2.13804,-4.20359 h 5.03708 c 0,0 3.66282,-0.22858 5.03706,1.37704 1.374245,1.60562 0.68574,3.89418 0.45716,5.4998 -0.22858,1.60283 -0.68573,3.89418 -2.28856,5.27122 -1.60283,1.37425 -4.50186,1.45231 -5.64755,1.6781 -1.14567,0.23137 -6.94653,-0.0753 -6.94653,-0.0753 0,0 -2.67324,-0.0752 -4.35133,-1.8342 -0.65228,-0.68295 0,-3.43702 0.45716,-5.4998 0.45994,-2.05999 1.37425,-4.35132 2.7485,-5.27122 1.37425,-0.91709 5.49701,-1.14567 5.49701,-1.14567"
id="path964" />
<path
style="fill:#008cc7;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.713609"
d="m 107.37108,148.28468 c -0.76377,0.61047 -1.07039,1.52756 -1.22093,2.44467 -0.15333,0.91709 -0.30383,2.13803 0,2.59518 0.30385,0.45996 1.8314,0.61327 1.8314,0.61327 h 3.50951 c 0,0 1.68088,0 2.44466,-0.45996 0.7638,-0.45715 0.91432,-1.37424 1.22094,-2.59518 0.30385,-1.22373 0.1505,-1.98751 0,-2.44467 -0.1505,-0.45995 -1.68089,-0.61326 -1.68089,-0.61326 h -3.96664 c 0,0 -1.37704,-0.1505 -2.13805,0.45995 z m 11.29229,-9.59748 h 4.73323 l -3.97222,19.09738 h -4.73323 l 0.15616,-1.9875 c 0,0 -0.092,0.61882 -1.8342,1.22373 -2.15755,0.74984 -3.8245,0.85298 -3.8245,0.85298 l -4.72485,-0.24252 c 0,0 -1.67531,0 -2.44188,-1.22093 -0.76101,-1.22373 -0.30385,-4.12556 0,-5.34929 0.30662,-1.22373 1.12338,-4.97295 2.7485,-6.11027 1.15404,-0.80838 2.44187,-1.0704 3.20567,-1.0704 0.76378,0 5.03706,0 5.03706,0 0,0 2.13805,0 2.74852,0.76378 0.61324,0.76378 1.0676,1.52756 1.0676,1.52756 l 1.8342,-7.48452"
id="path966" />
<path
style="fill:#008cc7;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.713609"
d="m 130.42119,147.97804 c -0.76378,0.61047 -1.06763,1.52758 -1.22094,2.44467 -0.15333,0.91711 -0.30384,2.13805 0,2.59798 0.30383,0.45715 1.83141,0.61046 1.83141,0.61046 h 3.51229 c 0,0 1.6781,0 2.44188,-0.45993 0.76099,-0.45715 0.91709,-1.37424 1.22094,-2.59518 0.30383,-1.22373 0.1505,-1.98753 0,-2.44467 -0.15333,-0.45716 -1.6781,-0.61326 -1.6781,-0.61326 h -3.96945 c 0,0 -1.37425,-0.1505 -2.13803,0.45993 z m -2.44746,9.34661 -5.03706,0.15333 4.12277,-19.09459 h 4.73044 l -1.6781,7.63783 c 0,0 1.22094,-1.22652 2.59519,-1.68089 1.37147,-0.45993 4.57992,-0.61047 4.57992,-0.61047 0,0 3.51229,-0.15333 4.88375,0.7638 1.37425,0.9143 2.13802,1.83418 1.06763,5.95974 -1.06763,4.12276 -1.7422,5.2322 -2.89904,6.10748 -0.87807,0.669 -3.66281,1.37703 -5.80365,1.37703 -2.13246,0 -4.27328,0.1505 -6.10469,-2.59797 l -0.45716,1.98473"
id="path968" />
<path
style="fill:#008cc7;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.713609"
d="m 146.64742,144.14798 h 5.03706 l -1.37425,6.45593 c -0.17558,1.02859 -0.87807,2.89066 0.68574,3.30601 1.98471,0.52964 5.94023,0.6272 7.19183,-1.87601 0.64393,-1.28783 2.04884,-7.88593 2.04884,-7.88593 h 4.73044 l -2.74851,13.6366 h -4.88654 l 0.76377,-2.59797 c 0,0 -0.91429,0.76378 -2.13523,1.37424 -1.22373,0.61327 -2.59521,1.53037 -5.80086,1.37704 -3.20845,-0.15333 -5.64755,-1.37704 -5.3437,-3.66837 0.30383,-2.29136 1.83141,-10.12154 1.83141,-10.12154"
id="path970" />
<g
clip-path="url(#clip4)"
clip-rule="nonzero"
id="g974"
transform="matrix(0.7136082,0,0,0.7136082,-10.979154,110.48574)">
<path
style="fill:#008cc7;fill-opacity:1;fill-rule:nonzero;stroke:none"
d="m 267.16016,52.363281 h 6.63281 c 0,0 0.63281,-2.773437 -0.85156,-3.851562 -2.12891,-1.542969 -3.64063,-1.925781 -6.41797,-1.925781 -2.78516,0 -7.70313,0 -7.70313,0 0,0 -2.46484,0.08984 -5.13281,1.070312 -1.90625,0.699219 -3.42578,2.140625 -3.85156,5.136719 -0.42969,2.996093 0,4.710937 2.99218,5.351562 2.9961,0.644531 7.0625,0 7.0625,0 0,0 5.5586,-0.210937 6.41797,0.859375 0.85157,1.070313 0.42578,1.710938 -0.85937,2.351563 -1.28516,0.640625 -3.63281,0.855469 -5.5586,0.855469 -1.92578,0 -4.70703,0 -5.13671,-0.855469 -0.42579,-0.855469 -0.42579,-1.5 -0.42579,-1.5 h -6.41796 c 0,0 -1.07032,3 -0.21485,3.855469 0.85938,0.855468 0.85938,2.570312 8.98438,2.785156 8.1289,0.210937 8.14453,-0.234375 9.84375,-0.429688 1.69922,-0.199218 4.48437,-1.285156 5.5625,-3.640625 1.0664,-2.351562 1.37109,-5.894531 0.85547,-6.636719 -0.95704,-1.367187 -3.21094,-1.925781 -5.13672,-1.925781 -1.92578,0 -9.62891,-0.214843 -9.62891,-0.214843 0,0 -2.13672,0.214843 -1.92187,-1.285157 0.21093,-1.5 2.99609,-1.5 4.92187,-1.5 1.92188,0 5.13281,0.214844 5.77344,0.859375 0.64062,0.640625 0.21094,0.640625 0.21094,0.640625"
id="path972" />
</g>
<path
style="fill:#2bb34a;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.713609"
d="m 40.481474,142.70405 c 0.730335,1.32964 1.87601,0.10033 1.87601,0.10033 l -1.485754,4.06981 -3.336677,-2.75966 c 0,0 1.608406,0.47945 1.569382,-1.03697 -0.04181,-1.51641 -1.970785,-8.63018 -2.701119,-9.95706 -0.730333,-1.32964 -1.876009,-0.10316 -1.876009,-0.10316 l 1.485753,-4.06701 3.336677,2.75687 c 0,0 -1.608406,-0.47666 -1.566592,1.03975 0.03902,1.51364 1.967998,8.62741 2.698329,9.95708"
id="path976" />
<path
style="fill:#2bb34a;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.713609"
d="m 46.577808,165.27748 c 0.730337,1.32964 1.876007,0.10316 1.876007,0.10316 l -1.48575,4.06979 -3.336678,-2.75966 c 0,0 1.608406,0.47667 1.56938,-1.03974 -0.04181,-1.51364 -1.970786,-8.62741 -2.701119,-9.95708 -0.727546,-1.32685 -1.87601,-0.10033 -1.87601,-0.10033 l 1.485756,-4.06699 3.336675,2.75687 c 0,0 -1.608406,-0.47947 -1.56938,1.03696 0.04181,1.51641 1.970785,8.63018 2.701119,9.95706"
id="path978" />
<path
style="fill:#2bb34a;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.713609"
d="m 46.608472,145.07624 c -0.786085,1.29618 0.850193,1.67807 0.850193,1.67807 l -4.264921,0.74428 0.719184,-4.27049 c 0,0 0.390254,1.6335 1.683669,0.84182 1.290628,-0.79444 6.481008,-6.02106 7.264308,-7.32004 0.78608,-1.29621 -0.8502,-1.6781 -0.8502,-1.6781 l 4.26493,-0.74428 -0.71919,4.27049 c 0,0 -0.39025,-1.63349 -1.68088,-0.83902 -1.29341,0.79165 -6.4838,6.02106 -7.267093,7.31727"
id="path980" />
<path
style="fill:#2bb34a;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.713609"
d="m 30.123007,161.6481 c -0.786085,1.29621 0.847408,1.6781 0.847408,1.6781 l -4.262136,0.74707 0.719184,-4.2733 c 0,0 0.390254,1.63349 1.680882,0.84184 1.290628,-0.79445 6.48101,-6.02107 7.267095,-7.32007 0.786084,-1.2962 -0.850196,-1.6753 -0.850196,-1.6753 l 4.262136,-0.74705 -0.719184,4.27049 c 0,0 -0.387466,-1.63349 -1.680882,-0.84184 -1.290626,0.79446 -6.481012,6.02385 -7.264307,7.32006"
id="path982" />
<path
style="fill:#2bb34a;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.713609"
d="m 47.617555,151.57117 c -1.516416,-0.0307 -1.02581,1.57497 -1.02581,1.57497 l -2.779169,-3.31996 4.055859,-1.51083 c 0,0 -1.218152,1.15402 0.11429,1.87601 1.33244,0.72197 8.4518,2.60633 9.96543,2.63979 1.51642,0.0307 1.0286,-1.57775 1.0286,-1.57775 l 2.77638,3.32274 -4.05586,1.51085 c 0,0 1.21815,-1.15405 -0.11429,-1.87601 -1.33244,-0.72199 -8.4518,-2.60635 -9.96543,-2.63981"
id="path984" />
<path
style="fill:#2bb34a;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.713609"
d="m 25.03576,145.56963 c -1.516418,-0.0334 -1.028599,1.57495 -1.028599,1.57495 l -2.77917,-3.32274 4.055858,-1.51085 c 0,0 -1.21815,1.15405 0.11429,1.87601 1.335227,0.72197 8.451798,2.60913 9.968214,2.63979 1.51363,0.0334 1.025811,-1.57495 1.025811,-1.57495 l 2.776384,3.32273 -4.05586,1.51085 c 0,0 1.22094,-1.15404 -0.111498,-1.8788 -1.332442,-0.71917 -8.451798,-2.60633 -9.965428,-2.63699"
id="path986" />
<path
style="fill:#008cc7;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.713609"
d="m 44.501097,157.93789 h 5.954168 l 2.97708,-13.51952 5.03707,13.29094 h 5.03708 l 10.76544,-13.29094 -2.7485,13.51952 h 5.49422 l 4.35134,-19.01932 h -9.15983 l -9.61698,11.68534 -4.34856,-11.91671 h -9.61977 l -4.122758,19.25069"
id="path988" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 13 KiB

26
docs/index.md Normal file
View File

@@ -0,0 +1,26 @@
---
_layout: landing
---
# Modbus Protocol for .NET
This library implements the basic Modbus protocol specified at [modbus.org](https://modbus.org/tech.php).
The aim was to include all necessary steps to have a fully working client, which is capable of the common protocol versions.
## NuGet packages
Here is an overview of the latest packages.
| Package Url | Version | Short description |
|-------------|---------|-------------------|
| [AMWD.Protocols.Modbus.Common] | ![NuGet Version: Common](https://img.shields.io/nuget/v/AMWD.Protocols.Modbus.Common?style=flat-square&logo=nuget) | Common data for Modbus protocol. |
| [AMWD.Protocols.Modbus.Serial] | ![NuGet Version: Serial](https://img.shields.io/nuget/v/AMWD.Protocols.Modbus.Serial?style=flat-square&logo=nuget) | Implementation of the Modbus protocol communicating via serial line using RTU or ASCII encoding. |
| [AMWD.Protocols.Modbus.Tcp] | ![NuGet Version: TCP](https://img.shields.io/nuget/v/AMWD.Protocols.Modbus.Tcp?style=flat-square&logo=nuget) | Implementation of the Modbus protocol communicating via TCP. |
[AMWD.Protocols.Modbus.Common]: https://www.nuget.org/packages/AMWD.Protocols.Modbus.Common
[AMWD.Protocols.Modbus.Serial]: https://www.nuget.org/packages/AMWD.Protocols.Modbus.Serial
[AMWD.Protocols.Modbus.Tcp]: https://www.nuget.org/packages/AMWD.Protocols.Modbus.Tcp

3
docs/templates/amwd/public/main.css vendored Normal file
View File

@@ -0,0 +1,3 @@
#logo {
margin-right: 8px;
}

4
docs/toc.yml Normal file
View File

@@ -0,0 +1,4 @@
- name: API
href: api/
- name: Articles
href: articles/

View File

@@ -1,8 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>netstandard2.0;net6.0;net8.0</TargetFrameworks>
<PackageId>AMWD.Protocols.Modbus.Common</PackageId>
<AssemblyName>amwd-modbus-common</AssemblyName>
<RootNamespace>AMWD.Protocols.Modbus.Common</RootNamespace>
@@ -12,8 +10,4 @@
<PackageTags>Modbus Protocol</PackageTags>
</PropertyGroup>
<ItemGroup>
<None Include="README.md" Pack="true" PackagePath="/" />
</ItemGroup>
</Project>

View File

@@ -1,8 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>netstandard2.0;net6.0;net8.0</TargetFrameworks>
<TargetFrameworks>netstandard2.0;net6.0;net8.0;net10.0</TargetFrameworks>
<PackageId>AMWD.Protocols.Modbus.Serial</PackageId>
<AssemblyName>amwd-modbus-serial</AssemblyName>
<RootNamespace>AMWD.Protocols.Modbus.Serial</RootNamespace>
@@ -13,14 +12,10 @@
</PropertyGroup>
<ItemGroup>
<Compile Include="$(SolutionDir)/AMWD.Protocols.Modbus.Common/Extensions/ArrayExtensions.cs" Link="Extensions/ArrayExtensions.cs" />
<Compile Include="$(SolutionDir)/AMWD.Protocols.Modbus.Common/Extensions/ReaderWriterLockSlimExtensions.cs" Link="Extensions/ReaderWriterLockSlimExtensions.cs" />
<Compile Include="$(SolutionDir)/AMWD.Protocols.Modbus.Common/Utils/AsyncQueue.cs" Link="Utils/AsyncQueue.cs" />
<Compile Include="$(SolutionDir)/AMWD.Protocols.Modbus.Common/Utils/RequestQueueItem.cs" Link="Utils/RequestQueueItem.cs" />
</ItemGroup>
<ItemGroup>
<None Include="README.md" Pack="true" PackagePath="/" />
<Compile Include="../AMWD.Protocols.Modbus.Common/Extensions/ArrayExtensions.cs" Link="Extensions/ArrayExtensions.cs" />
<Compile Include="../AMWD.Protocols.Modbus.Common/Extensions/ReaderWriterLockSlimExtensions.cs" Link="Extensions/ReaderWriterLockSlimExtensions.cs" />
<Compile Include="../AMWD.Protocols.Modbus.Common/Utils/AsyncQueue.cs" Link="Utils/AsyncQueue.cs" />
<Compile Include="../AMWD.Protocols.Modbus.Common/Utils/RequestQueueItem.cs" Link="Utils/RequestQueueItem.cs" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'netstandard2.0'">
@@ -35,8 +30,12 @@
<PackageReference Include="System.IO.Ports" Version="8.0.0" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'net10.0'">
<PackageReference Include="System.IO.Ports" Version="10.0.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="$(SolutionDir)\AMWD.Protocols.Modbus.Common\AMWD.Protocols.Modbus.Common.csproj" />
<ProjectReference Include="..\AMWD.Protocols.Modbus.Common\AMWD.Protocols.Modbus.Common.csproj" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,24 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<PackageId>AMWD.Protocols.Modbus.Tcp</PackageId>
<AssemblyName>amwd-modbus-tcp</AssemblyName>
<RootNamespace>AMWD.Protocols.Modbus.Tcp</RootNamespace>
<Product>Modbus TCP Protocol</Product>
<Description>Implementation of the Modbus protocol communicating via TCP.</Description>
<PackageTags>Modbus Protocol Network TCP LAN</PackageTags>
</PropertyGroup>
<ItemGroup>
<Compile Include="../AMWD.Protocols.Modbus.Common/Extensions/ArrayExtensions.cs" Link="Extensions/ArrayExtensions.cs" />
<Compile Include="../AMWD.Protocols.Modbus.Common/Extensions/ReaderWriterLockSlimExtensions.cs" Link="Extensions/ReaderWriterLockSlimExtensions.cs" />
<Compile Include="../AMWD.Protocols.Modbus.Common/Utils/AsyncQueue.cs" Link="Utils/AsyncQueue.cs" />
<Compile Include="../AMWD.Protocols.Modbus.Common/Utils/RequestQueueItem.cs" Link="Utils/RequestQueueItem.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\AMWD.Protocols.Modbus.Common\AMWD.Protocols.Modbus.Common.csproj" />
</ItemGroup>
</Project>

51
src/Directory.Build.props Normal file
View File

@@ -0,0 +1,51 @@
<Project>
<PropertyGroup>
<TargetFrameworks>netstandard2.0;net6.0;net8.0</TargetFrameworks>
<NrtContinuousIntegrationBuild>$(ContinuousIntegrationBuild)</NrtContinuousIntegrationBuild>
<AppendTargetFrameworkToOutputPath>true</AppendTargetFrameworkToOutputPath>
<CopyRefAssembliesToPublishDirectory>false</CopyRefAssembliesToPublishDirectory>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<RepositoryType>git</RepositoryType>
<RepositoryUrl>https://github.com/AM-WD/AMWD.Protocols.Modbus.git</RepositoryUrl>
<PublishRepositoryUrl>true</PublishRepositoryUrl>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<IncludeSymbols>true</IncludeSymbols>
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
<PackageIcon>package-icon.png</PackageIcon>
<PackageReadmeFile>README.md</PackageReadmeFile>
<PackageLicenseFile>LICENSE.txt</PackageLicenseFile>
<PackageProjectUrl>https://modbus.org/tech.php</PackageProjectUrl>
<AssemblyOriginatorKeyFile>../../AMWD.Protocols.Modbus.snk</AssemblyOriginatorKeyFile>
</PropertyGroup>
<PropertyGroup Condition="'$(CI)' == 'true'">
<ContinuousIntegrationBuild>true</ContinuousIntegrationBuild>
<EmbedUntrackedSources>true</EmbedUntrackedSources>
</PropertyGroup>
<ItemGroup Condition="'$(CI)' == 'true'">
<SourceLinkGiteaHost Include="$(CI_SERVER_HOST)" />
<PackageReference Include="Microsoft.SourceLink.Gitea" Version="8.0.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>
<ItemGroup>
<None Include="../../package-icon.png" Pack="true" PackagePath="/" />
<None Include="../../LICENSE.txt" Pack="true" PackagePath="/" />
<None Include="README.md" Pack="true" PackagePath="/" />
</ItemGroup>
<ItemGroup>
<InternalsVisibleTo Include="AMWD.Protocols.Modbus.Tests" PublicKey="$(PublicKey)" />
<InternalsVisibleTo Include="DynamicProxyGenAssembly2" PublicKey="$(MoqPublicKey)" />
</ItemGroup>
<Import Project="$([MSBuild]::GetPathOfFileAbove('Directory.Build.props', '$(MSBuildThisFileDirectory)\..'))" />
</Project>

View File

@@ -0,0 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup />
<ItemGroup>
<Compile Include="../MSTestSettings.cs" Link="MSTestSettings.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\AMWD.Protocols.Modbus.Serial\AMWD.Protocols.Modbus.Serial.csproj" />
<ProjectReference Include="..\..\src\AMWD.Protocols.Modbus.Tcp\AMWD.Protocols.Modbus.Tcp.csproj" />
</ItemGroup>
</Project>

View File

@@ -1,14 +1,15 @@
using System.Collections.Generic;
using System.Text;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Moq;
using AMWD.Protocols.Modbus.Common.Contracts;
namespace AMWD.Protocols.Modbus.Tests.Common.Contracts
{
[TestClass]
public class ModbusClientBaseTest
{
public TestContext TestContext { get; set; }
// Consts
private const byte UNIT_ID = 42;
private const ushort START_ADDRESS = 123;
@@ -111,10 +112,10 @@ namespace AMWD.Protocols.Modbus.Tests.Common.Contracts
IModbusConnection connection = null;
// Act + Assert
Assert.ThrowsException<ArgumentNullException>(() => new ModbusClientBaseWrapper(connection));
Assert.ThrowsExactly<ArgumentNullException>(() => new ModbusClientBaseWrapper(connection));
}
[DataTestMethod]
[TestMethod]
[DataRow(true)]
[DataRow(false)]
public void ShouldAlsoDisposeConnection(bool disposeConnection)
@@ -159,7 +160,7 @@ namespace AMWD.Protocols.Modbus.Tests.Common.Contracts
client.Dispose();
// Act + Assert
await Assert.ThrowsExceptionAsync<ObjectDisposedException>(() => client.ReadCoilsAsync(UNIT_ID, START_ADDRESS, READ_COUNT));
await Assert.ThrowsExactlyAsync<ObjectDisposedException>(() => client.ReadCoilsAsync(UNIT_ID, START_ADDRESS, READ_COUNT, TestContext.CancellationToken));
}
[TestMethod]
@@ -170,7 +171,7 @@ namespace AMWD.Protocols.Modbus.Tests.Common.Contracts
client.Protocol = null;
// Act + Assert
await Assert.ThrowsExceptionAsync<ArgumentNullException>(() => client.ReadCoilsAsync(UNIT_ID, START_ADDRESS, READ_COUNT));
await Assert.ThrowsExactlyAsync<ArgumentNullException>(() => client.ReadCoilsAsync(UNIT_ID, START_ADDRESS, READ_COUNT, TestContext.CancellationToken));
}
#endregion Common/Connection/Assertions
@@ -185,11 +186,11 @@ namespace AMWD.Protocols.Modbus.Tests.Common.Contracts
var client = GetClient();
// Act
var result = await client.ReadCoilsAsync(UNIT_ID, START_ADDRESS, READ_COUNT);
var result = await client.ReadCoilsAsync(UNIT_ID, START_ADDRESS, READ_COUNT, TestContext.CancellationToken);
// Assert
Assert.IsNotNull(result);
Assert.AreEqual(READ_COUNT, result.Count);
Assert.HasCount(READ_COUNT, result);
for (int i = 0; i < READ_COUNT; i++)
{
@@ -214,11 +215,11 @@ namespace AMWD.Protocols.Modbus.Tests.Common.Contracts
var client = GetClient();
// Act
var result = await client.ReadDiscreteInputsAsync(UNIT_ID, START_ADDRESS, READ_COUNT);
var result = await client.ReadDiscreteInputsAsync(UNIT_ID, START_ADDRESS, READ_COUNT, TestContext.CancellationToken);
// Assert
Assert.IsNotNull(result);
Assert.AreEqual(READ_COUNT, result.Count);
Assert.HasCount(READ_COUNT, result);
for (int i = 0; i < READ_COUNT; i++)
{
@@ -242,11 +243,11 @@ namespace AMWD.Protocols.Modbus.Tests.Common.Contracts
var client = GetClient();
// Act
var result = await client.ReadHoldingRegistersAsync(UNIT_ID, START_ADDRESS, READ_COUNT);
var result = await client.ReadHoldingRegistersAsync(UNIT_ID, START_ADDRESS, READ_COUNT, TestContext.CancellationToken);
// Assert
Assert.IsNotNull(result);
Assert.AreEqual(READ_COUNT, result.Count);
Assert.HasCount(READ_COUNT, result);
for (int i = 0; i < READ_COUNT; i++)
{
@@ -270,11 +271,11 @@ namespace AMWD.Protocols.Modbus.Tests.Common.Contracts
var client = GetClient();
// Act
var result = await client.ReadInputRegistersAsync(UNIT_ID, START_ADDRESS, READ_COUNT);
var result = await client.ReadInputRegistersAsync(UNIT_ID, START_ADDRESS, READ_COUNT, TestContext.CancellationToken);
// Assert
Assert.IsNotNull(result);
Assert.AreEqual(READ_COUNT, result.Count);
Assert.HasCount(READ_COUNT, result);
for (int i = 0; i < READ_COUNT; i++)
{
@@ -298,7 +299,7 @@ namespace AMWD.Protocols.Modbus.Tests.Common.Contracts
var client = GetClient();
// Act
var result = await client.ReadDeviceIdentificationAsync(UNIT_ID, ModbusDeviceIdentificationCategory.Basic, ModbusDeviceIdentificationObject.VendorName);
var result = await client.ReadDeviceIdentificationAsync(UNIT_ID, ModbusDeviceIdentificationCategory.Basic, ModbusDeviceIdentificationObject.VendorName, TestContext.CancellationToken);
// Assert
Assert.IsNotNull(result);
@@ -311,7 +312,7 @@ namespace AMWD.Protocols.Modbus.Tests.Common.Contracts
Assert.AreEqual("UnitTests", result.ModelName);
Assert.AreEqual("Modbus Client Base Unit Test", result.UserApplicationName);
Assert.AreEqual(0, result.ExtendedObjects.Count);
Assert.IsEmpty(result.ExtendedObjects);
_connection.Verify(c => c.InvokeAsync(It.IsAny<IReadOnlyList<byte>>(), It.IsAny<Func<IReadOnlyList<byte>, bool>>(), It.IsAny<CancellationToken>()), Times.Once);
_connection.VerifyNoOtherCalls();
@@ -341,7 +342,7 @@ namespace AMWD.Protocols.Modbus.Tests.Common.Contracts
var client = GetClient();
// Act
var result = await client.ReadDeviceIdentificationAsync(UNIT_ID, ModbusDeviceIdentificationCategory.Extended, ModbusDeviceIdentificationObject.VendorName);
var result = await client.ReadDeviceIdentificationAsync(UNIT_ID, ModbusDeviceIdentificationCategory.Extended, ModbusDeviceIdentificationObject.VendorName, TestContext.CancellationToken);
// Assert
Assert.IsNotNull(result);
@@ -354,7 +355,7 @@ namespace AMWD.Protocols.Modbus.Tests.Common.Contracts
Assert.AreEqual("UnitTests", result.ModelName);
Assert.AreEqual("Modbus Client Base Unit Test", result.UserApplicationName);
Assert.AreEqual(1, result.ExtendedObjects.Count);
Assert.HasCount(1, result.ExtendedObjects);
Assert.AreEqual(0x07, result.ExtendedObjects.First().Key);
CollectionAssert.AreEqual(new byte[] { 0x01, 0x02, 0x03 }, result.ExtendedObjects.First().Value);
@@ -384,7 +385,7 @@ namespace AMWD.Protocols.Modbus.Tests.Common.Contracts
var client = GetClient();
// Act
bool result = await client.WriteSingleCoilAsync(UNIT_ID, coil);
bool result = await client.WriteSingleCoilAsync(UNIT_ID, coil, TestContext.CancellationToken);
// Assert
Assert.IsTrue(result);
@@ -410,7 +411,7 @@ namespace AMWD.Protocols.Modbus.Tests.Common.Contracts
var client = GetClient();
// Act
bool result = await client.WriteSingleCoilAsync(UNIT_ID, coil);
bool result = await client.WriteSingleCoilAsync(UNIT_ID, coil, TestContext.CancellationToken);
// Assert
Assert.IsFalse(result);
@@ -436,7 +437,7 @@ namespace AMWD.Protocols.Modbus.Tests.Common.Contracts
var client = GetClient();
// Act
bool result = await client.WriteSingleCoilAsync(UNIT_ID, coil);
bool result = await client.WriteSingleCoilAsync(UNIT_ID, coil, TestContext.CancellationToken);
// Assert
Assert.IsFalse(result);
@@ -462,7 +463,7 @@ namespace AMWD.Protocols.Modbus.Tests.Common.Contracts
var client = GetClient();
// Act
bool result = await client.WriteSingleHoldingRegisterAsync(UNIT_ID, register);
bool result = await client.WriteSingleHoldingRegisterAsync(UNIT_ID, register, TestContext.CancellationToken);
// Assert
Assert.IsTrue(result);
@@ -488,7 +489,7 @@ namespace AMWD.Protocols.Modbus.Tests.Common.Contracts
var client = GetClient();
// Act
bool result = await client.WriteSingleHoldingRegisterAsync(UNIT_ID, register);
bool result = await client.WriteSingleHoldingRegisterAsync(UNIT_ID, register, TestContext.CancellationToken);
// Assert
Assert.IsFalse(result);
@@ -514,7 +515,7 @@ namespace AMWD.Protocols.Modbus.Tests.Common.Contracts
var client = GetClient();
// Act
bool result = await client.WriteSingleHoldingRegisterAsync(UNIT_ID, register);
bool result = await client.WriteSingleHoldingRegisterAsync(UNIT_ID, register, TestContext.CancellationToken);
// Assert
Assert.IsFalse(result);
@@ -544,7 +545,7 @@ namespace AMWD.Protocols.Modbus.Tests.Common.Contracts
var client = GetClient();
// Act
bool result = await client.WriteMultipleCoilsAsync(UNIT_ID, coils);
bool result = await client.WriteMultipleCoilsAsync(UNIT_ID, coils, TestContext.CancellationToken);
// Assert
Assert.IsTrue(result);
@@ -575,7 +576,7 @@ namespace AMWD.Protocols.Modbus.Tests.Common.Contracts
var client = GetClient();
// Act
bool result = await client.WriteMultipleCoilsAsync(UNIT_ID, coils);
bool result = await client.WriteMultipleCoilsAsync(UNIT_ID, coils, TestContext.CancellationToken);
// Assert
Assert.IsFalse(result);
@@ -606,7 +607,7 @@ namespace AMWD.Protocols.Modbus.Tests.Common.Contracts
var client = GetClient();
// Act
bool result = await client.WriteMultipleCoilsAsync(UNIT_ID, coils);
bool result = await client.WriteMultipleCoilsAsync(UNIT_ID, coils, TestContext.CancellationToken);
// Assert
Assert.IsFalse(result);
@@ -636,7 +637,7 @@ namespace AMWD.Protocols.Modbus.Tests.Common.Contracts
var client = GetClient();
// Act
bool result = await client.WriteMultipleHoldingRegistersAsync(UNIT_ID, registers);
bool result = await client.WriteMultipleHoldingRegistersAsync(UNIT_ID, registers, TestContext.CancellationToken);
// Assert
Assert.IsTrue(result);
@@ -667,7 +668,7 @@ namespace AMWD.Protocols.Modbus.Tests.Common.Contracts
var client = GetClient();
// Act
bool result = await client.WriteMultipleHoldingRegistersAsync(UNIT_ID, registers);
bool result = await client.WriteMultipleHoldingRegistersAsync(UNIT_ID, registers, TestContext.CancellationToken);
// Assert
Assert.IsFalse(result);
@@ -698,7 +699,7 @@ namespace AMWD.Protocols.Modbus.Tests.Common.Contracts
var client = GetClient();
// Act
bool result = await client.WriteMultipleHoldingRegistersAsync(UNIT_ID, registers);
bool result = await client.WriteMultipleHoldingRegistersAsync(UNIT_ID, registers, TestContext.CancellationToken);
// Assert
Assert.IsFalse(result);

View File

@@ -47,7 +47,7 @@
HoldingRegister[] registers = null;
// Act + Assert
Assert.ThrowsException<ArgumentNullException>(() => registers.GetSingle(0));
Assert.ThrowsExactly<ArgumentNullException>(() => registers.GetSingle(0));
}
[TestMethod]
@@ -60,10 +60,10 @@
};
// Act + Assert
Assert.ThrowsException<ArgumentException>(() => registers.GetSingle(0));
Assert.ThrowsExactly<ArgumentException>(() => registers.GetSingle(0));
}
[DataTestMethod]
[TestMethod]
[DataRow(1)]
[DataRow(-1)]
public void ShouldThrowArgumentOutOfRangeOnGetSingle(int startIndex)
@@ -76,7 +76,7 @@
};
// Act + Assert
Assert.ThrowsException<ArgumentOutOfRangeException>(() => registers.GetSingle(startIndex));
Assert.ThrowsExactly<ArgumentOutOfRangeException>(() => registers.GetSingle(startIndex));
}
[TestMethod]
@@ -90,7 +90,7 @@
};
// Act + Assert
Assert.ThrowsException<ArgumentException>(() => registers.GetSingle(0));
Assert.ThrowsExactly<ArgumentException>(() => registers.GetSingle(0));
}
[TestMethod]
@@ -139,7 +139,7 @@
HoldingRegister[] registers = null;
// Act + Assert
Assert.ThrowsException<ArgumentNullException>(() => registers.GetDouble(0));
Assert.ThrowsExactly<ArgumentNullException>(() => registers.GetDouble(0));
}
[TestMethod]
@@ -154,10 +154,10 @@
};
// Act + Assert
Assert.ThrowsException<ArgumentException>(() => registers.GetDouble(0));
Assert.ThrowsExactly<ArgumentException>(() => registers.GetDouble(0));
}
[DataTestMethod]
[TestMethod]
[DataRow(1)]
[DataRow(-1)]
public void ShouldThrowArgumentOutOfRangeOnGetDouble(int startIndex)
@@ -172,7 +172,7 @@
};
// Act + Assert
Assert.ThrowsException<ArgumentOutOfRangeException>(() => registers.GetDouble(startIndex));
Assert.ThrowsExactly<ArgumentOutOfRangeException>(() => registers.GetDouble(startIndex));
}
[TestMethod]
@@ -188,7 +188,7 @@
};
// Act + Assert
Assert.ThrowsException<ArgumentException>(() => registers.GetDouble(0));
Assert.ThrowsExactly<ArgumentException>(() => registers.GetDouble(0));
}
#endregion Modbus to value
@@ -206,7 +206,7 @@
// Assert
Assert.IsNotNull(registers);
Assert.AreEqual(2, registers.Count);
Assert.HasCount(2, registers);
Assert.AreEqual(5, registers[0].Address);
Assert.AreEqual(0x41, registers[0].HighByte);
@@ -228,7 +228,7 @@
// Assert
Assert.IsNotNull(registers);
Assert.AreEqual(2, registers.Count);
Assert.HasCount(2, registers);
Assert.AreEqual(6, registers[0].Address);
Assert.AreEqual(0x41, registers[0].HighByte);
@@ -250,7 +250,7 @@
// Assert
Assert.IsNotNull(registers);
Assert.AreEqual(4, registers.Count);
Assert.HasCount(4, registers);
Assert.AreEqual(5, registers[0].Address);
Assert.AreEqual(0x40, registers[0].HighByte);
@@ -280,7 +280,7 @@
// Assert
Assert.IsNotNull(registers);
Assert.AreEqual(4, registers.Count);
Assert.HasCount(4, registers);
Assert.AreEqual(8, registers[0].Address);
Assert.AreEqual(0x40, registers[0].HighByte);

View File

@@ -36,7 +36,7 @@ namespace AMWD.Protocols.Modbus.Tests.Common.Extensions
Coil coil = null;
// Act + Assert
Assert.ThrowsException<ArgumentNullException>(() => coil.GetBoolean());
Assert.ThrowsExactly<ArgumentNullException>(() => coil.GetBoolean());
}
[TestMethod]
@@ -98,7 +98,7 @@ namespace AMWD.Protocols.Modbus.Tests.Common.Extensions
HoldingRegister[] list = null;
// Act + Assert
Assert.ThrowsException<ArgumentNullException>(() => list.GetString(2));
Assert.ThrowsExactly<ArgumentNullException>(() => list.GetString(2));
}
[TestMethod]
@@ -108,10 +108,10 @@ namespace AMWD.Protocols.Modbus.Tests.Common.Extensions
var registers = Array.Empty<HoldingRegister>();
// Act + Assert
Assert.ThrowsException<ArgumentException>(() => registers.GetString(2));
Assert.ThrowsExactly<ArgumentException>(() => registers.GetString(2));
}
[DataTestMethod]
[TestMethod]
[DataRow(1)]
[DataRow(-1)]
public void ShouldThrowArgumentOutOfRangeOnString(int startIndex)
@@ -124,7 +124,7 @@ namespace AMWD.Protocols.Modbus.Tests.Common.Extensions
};
// Act + Assert
Assert.ThrowsException<ArgumentOutOfRangeException>(() => registers.GetString(2, startIndex));
Assert.ThrowsExactly<ArgumentOutOfRangeException>(() => registers.GetString(2, startIndex));
}
[TestMethod]
@@ -138,7 +138,7 @@ namespace AMWD.Protocols.Modbus.Tests.Common.Extensions
};
// Act + Assert
Assert.ThrowsException<ArgumentException>(() => registers.GetString(2));
Assert.ThrowsExactly<ArgumentException>(() => registers.GetString(2));
}
#endregion Modbus to value
@@ -172,7 +172,7 @@ namespace AMWD.Protocols.Modbus.Tests.Common.Extensions
// Assert
Assert.IsNotNull(register);
Assert.AreEqual(321, register.Address);
Assert.IsTrue(register.Value > 0);
Assert.IsGreaterThan(0, register.Value);
}
[TestMethod]
@@ -187,7 +187,7 @@ namespace AMWD.Protocols.Modbus.Tests.Common.Extensions
// Assert
Assert.IsNotNull(register);
Assert.AreEqual(321, register.Address);
Assert.IsTrue(register.Value == 0);
Assert.AreEqual(0, register.Value);
}
[TestMethod]
@@ -201,7 +201,7 @@ namespace AMWD.Protocols.Modbus.Tests.Common.Extensions
// Assert
Assert.IsNotNull(registers);
Assert.AreEqual(2, registers.Count);
Assert.HasCount(2, registers);
Assert.AreEqual(100, registers[0].Address);
Assert.AreEqual(97, registers[0].HighByte);
@@ -223,7 +223,7 @@ namespace AMWD.Protocols.Modbus.Tests.Common.Extensions
// Assert
Assert.IsNotNull(registers);
Assert.AreEqual(2, registers.Count);
Assert.HasCount(2, registers);
Assert.AreEqual(101, registers[0].Address);
Assert.AreEqual(97, registers[0].HighByte);
@@ -245,7 +245,7 @@ namespace AMWD.Protocols.Modbus.Tests.Common.Extensions
// Assert
Assert.IsNotNull(registers);
Assert.AreEqual(2, registers.Count);
Assert.HasCount(2, registers);
Assert.AreEqual(100, registers[0].Address);
Assert.AreEqual(97, registers[0].LowByte);
@@ -263,7 +263,7 @@ namespace AMWD.Protocols.Modbus.Tests.Common.Extensions
string str = null;
// Act + Assert
Assert.ThrowsException<ArgumentNullException>(() => str.ToRegisters(100).ToArray());
Assert.ThrowsExactly<ArgumentNullException>(() => str.ToRegisters(100).ToArray());
}
#endregion Value to Modbus

View File

@@ -38,7 +38,7 @@
HoldingRegister register = null;
// Act + Assert
Assert.ThrowsException<ArgumentNullException>(() => register.GetSByte());
Assert.ThrowsExactly<ArgumentNullException>(() => register.GetSByte());
}
[TestMethod]
@@ -48,7 +48,7 @@
var obj = new Coil();
// Act + Assert
Assert.ThrowsException<ArgumentException>(() => obj.GetSByte());
Assert.ThrowsExactly<ArgumentException>(() => obj.GetSByte());
}
[TestMethod]
@@ -84,7 +84,7 @@
HoldingRegister register = null;
// Act + Assert
Assert.ThrowsException<ArgumentNullException>(() => register.GetInt16());
Assert.ThrowsExactly<ArgumentNullException>(() => register.GetInt16());
}
[TestMethod]
@@ -94,7 +94,7 @@
var obj = new Coil();
// Act + Assert
Assert.ThrowsException<ArgumentException>(() => obj.GetInt16());
Assert.ThrowsExactly<ArgumentException>(() => obj.GetInt16());
}
[TestMethod]
@@ -103,9 +103,9 @@
// Arrange
var registers = new HoldingRegister[]
{
new HoldingRegister(),
new HoldingRegister { Address = 100, HighByte = 0x01, LowByte = 0x02 },
new HoldingRegister { Address = 101, HighByte = 0x03, LowByte = 0x04 }
new(),
new() { Address = 100, HighByte = 0x01, LowByte = 0x02 },
new() { Address = 101, HighByte = 0x03, LowByte = 0x04 }
};
// Act
@@ -121,8 +121,8 @@
// Arrange
var registers = new HoldingRegister[]
{
new HoldingRegister { Address = 101, HighByte = 0x01, LowByte = 0x02 },
new HoldingRegister { Address = 100, HighByte = 0x03, LowByte = 0x04 }
new() { Address = 101, HighByte = 0x01, LowByte = 0x02 },
new() { Address = 100, HighByte = 0x03, LowByte = 0x04 }
};
// Act
@@ -139,7 +139,7 @@
HoldingRegister[] registers = null;
// Act + Assert
Assert.ThrowsException<ArgumentNullException>(() => registers.GetInt32(0));
Assert.ThrowsExactly<ArgumentNullException>(() => registers.GetInt32(0));
}
[TestMethod]
@@ -148,14 +148,14 @@
// Arrange
var registers = new HoldingRegister[]
{
new HoldingRegister { Address = 101, HighByte = 0x01, LowByte = 0x02 }
new() { Address = 101, HighByte = 0x01, LowByte = 0x02 }
};
// Act + Assert
Assert.ThrowsException<ArgumentException>(() => registers.GetInt32(0));
Assert.ThrowsExactly<ArgumentException>(() => registers.GetInt32(0));
}
[DataTestMethod]
[TestMethod]
[DataRow(1)]
[DataRow(-1)]
public void ShouldThrowArgumentOutOfRangeOnGetInt32(int startIndex)
@@ -163,12 +163,12 @@
// Arrange
var registers = new HoldingRegister[]
{
new HoldingRegister { Address = 101, HighByte = 0x01, LowByte = 0x02 },
new HoldingRegister { Address = 100, HighByte = 0x03, LowByte = 0x04 }
new() { Address = 101, HighByte = 0x01, LowByte = 0x02 },
new() { Address = 100, HighByte = 0x03, LowByte = 0x04 }
};
// Act + Assert
Assert.ThrowsException<ArgumentOutOfRangeException>(() => registers.GetInt32(startIndex));
Assert.ThrowsExactly<ArgumentOutOfRangeException>(() => registers.GetInt32(startIndex));
}
[TestMethod]
@@ -182,7 +182,7 @@
};
// Act + Assert
Assert.ThrowsException<ArgumentException>(() => registers.GetInt32(0));
Assert.ThrowsExactly<ArgumentException>(() => registers.GetInt32(0));
}
[TestMethod]
@@ -191,11 +191,11 @@
// Arrange
var registers = new HoldingRegister[]
{
new HoldingRegister(),
new HoldingRegister { Address = 100, HighByte = 0x00, LowByte = 0x00 },
new HoldingRegister { Address = 101, HighByte = 0x00, LowByte = 0x00 },
new HoldingRegister { Address = 102, HighByte = 0x01, LowByte = 0x02 },
new HoldingRegister { Address = 103, HighByte = 0x03, LowByte = 0x04 }
new(),
new() { Address = 100, HighByte = 0x00, LowByte = 0x00 },
new() { Address = 101, HighByte = 0x00, LowByte = 0x00 },
new() { Address = 102, HighByte = 0x01, LowByte = 0x02 },
new() { Address = 103, HighByte = 0x03, LowByte = 0x04 }
};
// Act
@@ -211,10 +211,10 @@
// Arrange
var registers = new HoldingRegister[]
{
new HoldingRegister { Address = 103, HighByte = 0x00, LowByte = 0x00 },
new HoldingRegister { Address = 102, HighByte = 0x00, LowByte = 0x00 },
new HoldingRegister { Address = 101, HighByte = 0x01, LowByte = 0x02 },
new HoldingRegister { Address = 100, HighByte = 0x03, LowByte = 0x04 }
new() { Address = 103, HighByte = 0x00, LowByte = 0x00 },
new() { Address = 102, HighByte = 0x00, LowByte = 0x00 },
new() { Address = 101, HighByte = 0x01, LowByte = 0x02 },
new() { Address = 100, HighByte = 0x03, LowByte = 0x04 }
};
// Act
@@ -231,7 +231,7 @@
HoldingRegister[] registers = null;
// Act + Assert
Assert.ThrowsException<ArgumentNullException>(() => registers.GetInt64(0));
Assert.ThrowsExactly<ArgumentNullException>(() => registers.GetInt64(0));
}
[TestMethod]
@@ -240,16 +240,16 @@
// Arrange
var registers = new HoldingRegister[]
{
new HoldingRegister { Address = 101, HighByte = 0x00, LowByte = 0x00 },
new HoldingRegister { Address = 102, HighByte = 0x01, LowByte = 0x02 },
new HoldingRegister { Address = 103, HighByte = 0x03, LowByte = 0x04 }
new() { Address = 101, HighByte = 0x00, LowByte = 0x00 },
new() { Address = 102, HighByte = 0x01, LowByte = 0x02 },
new() { Address = 103, HighByte = 0x03, LowByte = 0x04 }
};
// Act + Assert
Assert.ThrowsException<ArgumentException>(() => registers.GetInt64(0));
Assert.ThrowsExactly<ArgumentException>(() => registers.GetInt64(0));
}
[DataTestMethod]
[TestMethod]
[DataRow(1)]
[DataRow(-1)]
public void ShouldThrowArgumentOutOfRangeOnGetInt64(int startIndex)
@@ -257,14 +257,14 @@
// Arrange
var registers = new HoldingRegister[]
{
new HoldingRegister { Address = 100, HighByte = 0x00, LowByte = 0x00 },
new HoldingRegister { Address = 101, HighByte = 0x00, LowByte = 0x00 },
new HoldingRegister { Address = 102, HighByte = 0x01, LowByte = 0x02 },
new HoldingRegister { Address = 103, HighByte = 0x03, LowByte = 0x04 }
new() { Address = 100, HighByte = 0x00, LowByte = 0x00 },
new() { Address = 101, HighByte = 0x00, LowByte = 0x00 },
new() { Address = 102, HighByte = 0x01, LowByte = 0x02 },
new() { Address = 103, HighByte = 0x03, LowByte = 0x04 }
};
// Act + Assert
Assert.ThrowsException<ArgumentOutOfRangeException>(() => registers.GetInt64(startIndex));
Assert.ThrowsExactly<ArgumentOutOfRangeException>(() => registers.GetInt64(startIndex));
}
[TestMethod]
@@ -280,7 +280,7 @@
};
// Act + Assert
Assert.ThrowsException<ArgumentException>(() => registers.GetInt64(0));
Assert.ThrowsExactly<ArgumentException>(() => registers.GetInt64(0));
}
#endregion Modbus to value
@@ -330,7 +330,7 @@
// Assert
Assert.IsNotNull(registers);
Assert.AreEqual(2, registers.Count);
Assert.HasCount(2, registers);
Assert.AreEqual(5, registers[0].Address);
Assert.AreEqual(0x00, registers[0].HighByte);
@@ -352,7 +352,7 @@
// Assert
Assert.IsNotNull(registers);
Assert.AreEqual(2, registers.Count);
Assert.HasCount(2, registers);
Assert.AreEqual(6, registers[0].Address);
Assert.AreEqual(0x00, registers[0].HighByte);
@@ -374,7 +374,7 @@
// Assert
Assert.IsNotNull(registers);
Assert.AreEqual(4, registers.Count);
Assert.HasCount(4, registers);
Assert.AreEqual(10, registers[0].Address);
Assert.AreEqual(0x00, registers[0].HighByte);
@@ -404,7 +404,7 @@
// Assert
Assert.IsNotNull(registers);
Assert.AreEqual(4, registers.Count);
Assert.HasCount(4, registers);
Assert.AreEqual(13, registers[0].Address);
Assert.AreEqual(0x00, registers[0].HighByte);

View File

@@ -38,7 +38,7 @@
HoldingRegister register = null;
// Act + Assert
Assert.ThrowsException<ArgumentNullException>(() => register.GetByte());
Assert.ThrowsExactly<ArgumentNullException>(() => register.GetByte());
}
[TestMethod]
@@ -48,7 +48,7 @@
var obj = new Coil();
// Act + Assert
Assert.ThrowsException<ArgumentException>(() => obj.GetByte());
Assert.ThrowsExactly<ArgumentException>(() => obj.GetByte());
}
[TestMethod]
@@ -84,7 +84,7 @@
HoldingRegister register = null;
// Act + Assert
Assert.ThrowsException<ArgumentNullException>(() => register.GetUInt16());
Assert.ThrowsExactly<ArgumentNullException>(() => register.GetUInt16());
}
[TestMethod]
@@ -94,7 +94,7 @@
var obj = new Coil();
// Act + Assert
Assert.ThrowsException<ArgumentException>(() => obj.GetUInt16());
Assert.ThrowsExactly<ArgumentException>(() => obj.GetUInt16());
}
[TestMethod]
@@ -139,7 +139,7 @@
HoldingRegister[] registers = null;
// Act + Assert
Assert.ThrowsException<ArgumentNullException>(() => registers.GetUInt32(0));
Assert.ThrowsExactly<ArgumentNullException>(() => registers.GetUInt32(0));
}
[TestMethod]
@@ -152,10 +152,10 @@
};
// Act + Assert
Assert.ThrowsException<ArgumentException>(() => registers.GetUInt32(1));
Assert.ThrowsExactly<ArgumentException>(() => registers.GetUInt32(1));
}
[DataTestMethod]
[TestMethod]
[DataRow(1)]
[DataRow(-1)]
public void ShouldThrowArgumentOutOfRangeOnGetUInt32(int startIndex)
@@ -168,7 +168,7 @@
};
// Act + Assert
Assert.ThrowsException<ArgumentOutOfRangeException>(() => registers.GetUInt32(startIndex));
Assert.ThrowsExactly<ArgumentOutOfRangeException>(() => registers.GetUInt32(startIndex));
}
[TestMethod]
@@ -182,7 +182,7 @@
};
// Act + Assert
Assert.ThrowsException<ArgumentException>(() => registers.GetUInt32(0));
Assert.ThrowsExactly<ArgumentException>(() => registers.GetUInt32(0));
}
[TestMethod]
@@ -231,7 +231,7 @@
HoldingRegister[] registers = null;
// Act + Assert
Assert.ThrowsException<ArgumentNullException>(() => registers.GetUInt64(0));
Assert.ThrowsExactly<ArgumentNullException>(() => registers.GetUInt64(0));
}
[TestMethod]
@@ -246,10 +246,10 @@
};
// Act + Assert
Assert.ThrowsException<ArgumentException>(() => registers.GetUInt64(0));
Assert.ThrowsExactly<ArgumentException>(() => registers.GetUInt64(0));
}
[DataTestMethod]
[TestMethod]
[DataRow(1)]
[DataRow(-1)]
public void ShouldThrowArgumentOutOfRangeOnGetUInt64(int startIndex)
@@ -264,7 +264,7 @@
};
// Act + Assert
Assert.ThrowsException<ArgumentOutOfRangeException>(() => registers.GetUInt64(startIndex));
Assert.ThrowsExactly<ArgumentOutOfRangeException>(() => registers.GetUInt64(startIndex));
}
[TestMethod]
@@ -280,7 +280,7 @@
};
// Act + Assert
Assert.ThrowsException<ArgumentException>(() => registers.GetUInt64(0));
Assert.ThrowsExactly<ArgumentException>(() => registers.GetUInt64(0));
}
#endregion Modbus to value
@@ -330,7 +330,7 @@
// Assert
Assert.IsNotNull(registers);
Assert.AreEqual(2, registers.Count);
Assert.HasCount(2, registers);
Assert.AreEqual(5, registers[0].Address);
Assert.AreEqual(0x00, registers[0].HighByte);
@@ -352,7 +352,7 @@
// Assert
Assert.IsNotNull(registers);
Assert.AreEqual(2, registers.Count);
Assert.HasCount(2, registers);
Assert.AreEqual(6, registers[0].Address);
Assert.AreEqual(0x00, registers[0].HighByte);
@@ -374,7 +374,7 @@
// Assert
Assert.IsNotNull(registers);
Assert.AreEqual(4, registers.Count);
Assert.HasCount(4, registers);
Assert.AreEqual(10, registers[0].Address);
Assert.AreEqual(0x00, registers[0].HighByte);
@@ -404,7 +404,7 @@
// Assert
Assert.IsNotNull(registers);
Assert.AreEqual(4, registers.Count);
Assert.HasCount(4, registers);
Assert.AreEqual(13, registers[0].Address);
Assert.AreEqual(0x00, registers[0].HighByte);

View File

@@ -87,7 +87,7 @@
Assert.IsFalse(success);
}
[DataTestMethod]
[TestMethod]
[DataRow(0xFF)]
[DataRow(0x00)]
public void ShouldPrintPrettyString(int highByte)

View File

@@ -87,7 +87,7 @@
Assert.IsFalse(success);
}
[DataTestMethod]
[TestMethod]
[DataRow(0xFF)]
[DataRow(0x00)]
public void ShouldPrintPrettyString(int highByte)

View File

@@ -1,6 +1,5 @@
using System.Collections.Generic;
using AMWD.Protocols.Modbus.Common.Models;
using System.Reflection;
using AMWD.Protocols.Modbus.Common.Models;
namespace AMWD.Protocols.Modbus.Tests.Common.Models
{
@@ -134,7 +133,7 @@ namespace AMWD.Protocols.Modbus.Tests.Common.Models
.GetField("_coils", BindingFlags.NonPublic | BindingFlags.Instance)
.GetValue(device)).ToArray();
Assert.AreEqual(1, coils.Length);
Assert.HasCount(1, coils);
Assert.AreEqual(111, coils.First());
}
@@ -179,7 +178,7 @@ namespace AMWD.Protocols.Modbus.Tests.Common.Models
.GetField("_discreteInputs", BindingFlags.NonPublic | BindingFlags.Instance)
.GetValue(device)).ToArray();
Assert.AreEqual(1, discreteInputs.Length);
Assert.HasCount(1, discreteInputs);
Assert.AreEqual(111, discreteInputs.First());
}
@@ -229,7 +228,7 @@ namespace AMWD.Protocols.Modbus.Tests.Common.Models
.GetValue(device))
.ToDictionary(x => x.Key, x => x.Value);
Assert.AreEqual(1, registers.Count);
Assert.HasCount(1, registers);
Assert.AreEqual(111, registers.First().Key);
Assert.AreEqual(42, registers.First().Value);
}
@@ -280,7 +279,7 @@ namespace AMWD.Protocols.Modbus.Tests.Common.Models
.GetValue(device))
.ToDictionary(x => x.Key, x => x.Value);
Assert.AreEqual(1, registers.Count);
Assert.HasCount(1, registers);
Assert.AreEqual(111, registers.First().Key);
Assert.AreEqual(42, registers.First().Value);
}

Some files were not shown because too many files have changed in this diff Show More