mirror of
https://github.com/S7NetPlus/s7netplus.git
synced 2026-02-17 14:28:25 +08:00
Compare commits
273 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d10c15b80f | ||
|
|
5225c8bffd | ||
|
|
aa03400350 | ||
|
|
2b4ec6d9dd | ||
|
|
54f3de6c9f | ||
|
|
e6d14587d3 | ||
|
|
e63d92c61c | ||
|
|
b4b94e1777 | ||
|
|
13c25fc20b | ||
|
|
82e29837a2 | ||
|
|
1afb07774b | ||
|
|
051091919f | ||
|
|
478c1aed52 | ||
|
|
924eb9c48f | ||
|
|
eb8e188c86 | ||
|
|
37384d2a92 | ||
|
|
fdd4519f64 | ||
|
|
52c60f6eaf | ||
|
|
926d74f1d2 | ||
|
|
9b89acfb91 | ||
|
|
de0a9e64dc | ||
|
|
dfcc4c7408 | ||
|
|
c9a98fba95 | ||
|
|
40edecad43 | ||
|
|
0b04c86cb9 | ||
|
|
f03ba93a96 | ||
|
|
9cd63d906f | ||
|
|
d051b93bdc | ||
|
|
c9bab7523a | ||
|
|
a7608e3cb7 | ||
|
|
4d37679c75 | ||
|
|
e2a0ed548d | ||
|
|
4124bae1bc | ||
|
|
2bcc5e6b9c | ||
|
|
33981ab4f9 | ||
|
|
de60a7b6b0 | ||
|
|
de87409458 | ||
|
|
ca89736c7c | ||
|
|
4a72c3596b | ||
|
|
786e012179 | ||
|
|
f46833606f | ||
|
|
b95b71e9aa | ||
|
|
1069641606 | ||
|
|
36a9ecb2c8 | ||
|
|
243e868488 | ||
|
|
ff65f06b7d | ||
|
|
065b1fbdf8 | ||
|
|
8f3c701a2f | ||
|
|
023530322e | ||
|
|
9198fc1686 | ||
|
|
12a2e3c0b1 | ||
|
|
b088fe276b | ||
|
|
80ad95372b | ||
|
|
106e9912ab | ||
|
|
af39659944 | ||
|
|
e5bdb10ce3 | ||
|
|
faea428e4c | ||
|
|
4da76c7f6d | ||
|
|
6c4d4605f0 | ||
|
|
730ccbf9fc | ||
|
|
b36c4a98ec | ||
|
|
70c3f8e996 | ||
|
|
cf1b71220a | ||
|
|
88c45bd995 | ||
|
|
cf493d47f0 | ||
|
|
9e2f17fdf3 | ||
|
|
1919b0083a | ||
|
|
fd4bc0fe84 | ||
|
|
9ff73ff3f7 | ||
|
|
c31353bed2 | ||
|
|
b16097092b | ||
|
|
eca2ed6474 | ||
|
|
b92242f911 | ||
|
|
c99c3d745a | ||
|
|
3b2dbd1148 | ||
|
|
64c781ec8b | ||
|
|
e8a9983367 | ||
|
|
3c91aa02b0 | ||
|
|
edfa208c3e | ||
|
|
d11f46eedb | ||
|
|
09c8b18d3d | ||
|
|
10e5562706 | ||
|
|
7d570f93c1 | ||
|
|
c79ae13ea1 | ||
|
|
09851ec30b | ||
|
|
592d21c3aa | ||
|
|
d530f1e422 | ||
|
|
ba3dd084cb | ||
|
|
a047c5bba4 | ||
|
|
2bb7ac7d2a | ||
|
|
783c456dc9 | ||
|
|
688d4e2a28 | ||
|
|
bb0b57c574 | ||
|
|
2f07d43062 | ||
|
|
4ef037881c | ||
|
|
fbd8a13c6c | ||
|
|
2a451bc049 | ||
|
|
324ae95c42 | ||
|
|
bd8177d39e | ||
|
|
e68ca64596 | ||
|
|
647d4c7ae2 | ||
|
|
c7ef055be2 | ||
|
|
7035d22506 | ||
|
|
fc6781c37f | ||
|
|
3555436c04 | ||
|
|
3258c84fbc | ||
|
|
28257f28b3 | ||
|
|
a1d87de2d9 | ||
|
|
4be5765fc9 | ||
|
|
6614c7330a | ||
|
|
5d59c8284d | ||
|
|
6554b999c0 | ||
|
|
ff20687776 | ||
|
|
0b6226327b | ||
|
|
385240ba5e | ||
|
|
0a8ee0e091 | ||
|
|
1685270535 | ||
|
|
9a34b14e1e | ||
|
|
50f0e62573 | ||
|
|
9ea54be524 | ||
|
|
dcd5bb3437 | ||
|
|
8dc89867e9 | ||
|
|
798913c4c6 | ||
|
|
2fbf659136 | ||
|
|
6a84b6f124 | ||
|
|
b3cb45de37 | ||
|
|
4fcab9a167 | ||
|
|
94a178478b | ||
|
|
2a4485941f | ||
|
|
47cce5887d | ||
|
|
0e5651b37f | ||
|
|
1d1f1e76a9 | ||
|
|
555d1e8956 | ||
|
|
427d8124de | ||
|
|
735f1d4533 | ||
|
|
2aa4f08836 | ||
|
|
8d8b2ec36e | ||
|
|
cf64c65c23 | ||
|
|
93752a3485 | ||
|
|
229df2dfcd | ||
|
|
3b23ab76e7 | ||
|
|
3872e638aa | ||
|
|
e124c70fb1 | ||
|
|
b8b4071e39 | ||
|
|
b2183dd760 | ||
|
|
f2d33855ca | ||
|
|
b1d2d11904 | ||
|
|
23796de8bf | ||
|
|
02b38326c8 | ||
|
|
ea96891a31 | ||
|
|
2fbabd5517 | ||
|
|
800a790b89 | ||
|
|
0dbe401ce9 | ||
|
|
e623b535ac | ||
|
|
ce359789dc | ||
|
|
4ae905ffd5 | ||
|
|
70506e7dba | ||
|
|
20458d4b46 | ||
|
|
898b870221 | ||
|
|
0fd193e08f | ||
|
|
98df02d7d4 | ||
|
|
ae620f3c62 | ||
|
|
de084394a6 | ||
|
|
370fd6b3d9 | ||
|
|
fba3ffd5db | ||
|
|
e44cb1571c | ||
|
|
ab486e3d1f | ||
|
|
705743e5f1 | ||
|
|
fd17bfa03b | ||
|
|
8dad14955e | ||
|
|
96efb9d56a | ||
|
|
09d323925a | ||
|
|
bf4550655e | ||
|
|
214a7a73c8 | ||
|
|
a5d3c70373 | ||
|
|
2204ab360c | ||
|
|
a1b69a5c5a | ||
|
|
1538de148b | ||
|
|
ff7e13cd49 | ||
|
|
c651380647 | ||
|
|
0298371bfc | ||
|
|
ff1e5fdc26 | ||
|
|
bd50709ad7 | ||
|
|
cafca8e28e | ||
|
|
ab11cc8e3e | ||
|
|
9740224966 | ||
|
|
db50a62aad | ||
|
|
2f3bbddaef | ||
|
|
4ab73d0e3a | ||
|
|
932433ad69 | ||
|
|
d37c388d20 | ||
|
|
c13fb970d0 | ||
|
|
28a1225265 | ||
|
|
fc62bb79d4 | ||
|
|
b8b144d7ae | ||
|
|
98228924ea | ||
|
|
a1f4e44c48 | ||
|
|
2df9d0b0bf | ||
|
|
7821b6b6f6 | ||
|
|
e516675a70 | ||
|
|
710ab2e026 | ||
|
|
534ecb2546 | ||
|
|
66fe6750b2 | ||
|
|
85e1abfdb0 | ||
|
|
3409e52fef | ||
|
|
514dde365e | ||
|
|
0f151e4947 | ||
|
|
5f220cd31f | ||
|
|
6569e5e169 | ||
|
|
4bca9d8c19 | ||
|
|
229558d586 | ||
|
|
daf0f8e0d6 | ||
|
|
d9abebe550 | ||
|
|
2083ab1501 | ||
|
|
003d775228 | ||
|
|
e1c62c899b | ||
|
|
5a82313eb1 | ||
|
|
8d64bd89fc | ||
|
|
299918e293 | ||
|
|
740a47ab43 | ||
|
|
38d089e117 | ||
|
|
aaab24a4c2 | ||
|
|
0721b1a84a | ||
|
|
1b22badea1 | ||
|
|
ddfedaa17e | ||
|
|
2d24adc874 | ||
|
|
44bf1366e4 | ||
|
|
64e485c54a | ||
|
|
219c1cc71a | ||
|
|
a3277133af | ||
|
|
00e22ee214 | ||
|
|
8ac96162f9 | ||
|
|
1b34716a30 | ||
|
|
b8b890977e | ||
|
|
013ff5fd92 | ||
|
|
642cf8169e | ||
|
|
f6e370b162 | ||
|
|
cbaa8921df | ||
|
|
b3458a8304 | ||
|
|
a824344a4c | ||
|
|
587e496497 | ||
|
|
0d1bc472c8 | ||
|
|
e6f1114bc1 | ||
|
|
84aee0671a | ||
|
|
74af1c0da7 | ||
|
|
c80b0dd55d | ||
|
|
eb0d6a3429 | ||
|
|
f53a3bd320 | ||
|
|
4b04ed74a1 | ||
|
|
50b026d7a5 | ||
|
|
f740ba0078 | ||
|
|
1b4faf21d7 | ||
|
|
3a18d13805 | ||
|
|
9fd515280a | ||
|
|
d17fdf8efb | ||
|
|
8a3db22629 | ||
|
|
6470f8d076 | ||
|
|
723b0ffd42 | ||
|
|
bfeacee08f | ||
|
|
b6b53078f9 | ||
|
|
a99ea469ce | ||
|
|
dd71e1bf0b | ||
|
|
530072b70f | ||
|
|
117ad5cd1b | ||
|
|
7cedec5909 | ||
|
|
f6a2e11045 | ||
|
|
8005304827 | ||
|
|
ef5e060948 | ||
|
|
3178d2aa09 | ||
|
|
6a2bc708a9 | ||
|
|
ea84cd414f | ||
|
|
ad98783888 | ||
|
|
cddb826053 |
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<configuration>
|
||||
<solution>
|
||||
<add key="disableSourceControlIntegration" value="true" />
|
||||
</solution>
|
||||
</configuration>
|
||||
BIN
.nuget/NuGet.exe
BIN
.nuget/NuGet.exe
Binary file not shown.
@@ -1,144 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">$(MSBuildProjectDirectory)\..\</SolutionDir>
|
||||
|
||||
<!-- Enable the restore command to run before builds -->
|
||||
<RestorePackages Condition=" '$(RestorePackages)' == '' ">false</RestorePackages>
|
||||
|
||||
<!-- Property that enables building a package from a project -->
|
||||
<BuildPackage Condition=" '$(BuildPackage)' == '' ">false</BuildPackage>
|
||||
|
||||
<!-- Determines if package restore consent is required to restore packages -->
|
||||
<RequireRestoreConsent Condition=" '$(RequireRestoreConsent)' != 'false' ">true</RequireRestoreConsent>
|
||||
|
||||
<!-- Download NuGet.exe if it does not already exist -->
|
||||
<DownloadNuGetExe Condition=" '$(DownloadNuGetExe)' == '' ">false</DownloadNuGetExe>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup Condition=" '$(PackageSources)' == '' ">
|
||||
<!-- Package sources used to restore packages. By default, registered sources under %APPDATA%\NuGet\NuGet.Config will be used -->
|
||||
<!-- The official NuGet package source (https://www.nuget.org/api/v2/) will be excluded if package sources are specified and it does not appear in the list -->
|
||||
<!--
|
||||
<PackageSource Include="https://www.nuget.org/api/v2/" />
|
||||
<PackageSource Include="https://my-nuget-source/nuget/" />
|
||||
-->
|
||||
</ItemGroup>
|
||||
|
||||
<PropertyGroup Condition=" '$(OS)' == 'Windows_NT'">
|
||||
<!-- Windows specific commands -->
|
||||
<NuGetToolsPath>$([System.IO.Path]::Combine($(SolutionDir), ".nuget"))</NuGetToolsPath>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition=" '$(OS)' != 'Windows_NT'">
|
||||
<!-- We need to launch nuget.exe with the mono command if we're not on windows -->
|
||||
<NuGetToolsPath>$(SolutionDir).nuget</NuGetToolsPath>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<PackagesProjectConfig Condition=" '$(OS)' == 'Windows_NT'">$(MSBuildProjectDirectory)\packages.$(MSBuildProjectName.Replace(' ', '_')).config</PackagesProjectConfig>
|
||||
<PackagesProjectConfig Condition=" '$(OS)' != 'Windows_NT'">$(MSBuildProjectDirectory)\packages.$(MSBuildProjectName).config</PackagesProjectConfig>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<PackagesConfig Condition="Exists('$(MSBuildProjectDirectory)\packages.config')">$(MSBuildProjectDirectory)\packages.config</PackagesConfig>
|
||||
<PackagesConfig Condition="Exists('$(PackagesProjectConfig)')">$(PackagesProjectConfig)</PackagesConfig>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<!-- NuGet command -->
|
||||
<NuGetExePath Condition=" '$(NuGetExePath)' == '' ">$(NuGetToolsPath)\NuGet.exe</NuGetExePath>
|
||||
<PackageSources Condition=" $(PackageSources) == '' ">@(PackageSource)</PackageSources>
|
||||
|
||||
<NuGetCommand Condition=" '$(OS)' == 'Windows_NT'">"$(NuGetExePath)"</NuGetCommand>
|
||||
<NuGetCommand Condition=" '$(OS)' != 'Windows_NT' ">mono --runtime=v4.0.30319 "$(NuGetExePath)"</NuGetCommand>
|
||||
|
||||
<PackageOutputDir Condition="$(PackageOutputDir) == ''">$(TargetDir.Trim('\\'))</PackageOutputDir>
|
||||
|
||||
<RequireConsentSwitch Condition=" $(RequireRestoreConsent) == 'true' ">-RequireConsent</RequireConsentSwitch>
|
||||
<NonInteractiveSwitch Condition=" '$(VisualStudioVersion)' != '' AND '$(OS)' == 'Windows_NT' ">-NonInteractive</NonInteractiveSwitch>
|
||||
|
||||
<PaddedSolutionDir Condition=" '$(OS)' == 'Windows_NT'">"$(SolutionDir) "</PaddedSolutionDir>
|
||||
<PaddedSolutionDir Condition=" '$(OS)' != 'Windows_NT' ">"$(SolutionDir)"</PaddedSolutionDir>
|
||||
|
||||
<!-- Commands -->
|
||||
<RestoreCommand>$(NuGetCommand) install "$(PackagesConfig)" -source "$(PackageSources)" $(NonInteractiveSwitch) $(RequireConsentSwitch) -solutionDir $(PaddedSolutionDir)</RestoreCommand>
|
||||
<BuildCommand>$(NuGetCommand) pack "$(ProjectPath)" -Properties "Configuration=$(Configuration);Platform=$(Platform)" $(NonInteractiveSwitch) -OutputDirectory "$(PackageOutputDir)" -symbols</BuildCommand>
|
||||
|
||||
<!-- We need to ensure packages are restored prior to assembly resolve -->
|
||||
<BuildDependsOn Condition="$(RestorePackages) == 'true'">
|
||||
RestorePackages;
|
||||
$(BuildDependsOn);
|
||||
</BuildDependsOn>
|
||||
|
||||
<!-- Make the build depend on restore packages -->
|
||||
<BuildDependsOn Condition="$(BuildPackage) == 'true'">
|
||||
$(BuildDependsOn);
|
||||
BuildPackage;
|
||||
</BuildDependsOn>
|
||||
</PropertyGroup>
|
||||
|
||||
<Target Name="CheckPrerequisites">
|
||||
<!-- Raise an error if we're unable to locate nuget.exe -->
|
||||
<Error Condition="'$(DownloadNuGetExe)' != 'true' AND !Exists('$(NuGetExePath)')" Text="Unable to locate '$(NuGetExePath)'" />
|
||||
<!--
|
||||
Take advantage of MsBuild's build dependency tracking to make sure that we only ever download nuget.exe once.
|
||||
This effectively acts as a lock that makes sure that the download operation will only happen once and all
|
||||
parallel builds will have to wait for it to complete.
|
||||
-->
|
||||
<MsBuild Targets="_DownloadNuGet" Projects="$(MSBuildThisFileFullPath)" Properties="Configuration=NOT_IMPORTANT;DownloadNuGetExe=$(DownloadNuGetExe)" />
|
||||
</Target>
|
||||
|
||||
<Target Name="_DownloadNuGet">
|
||||
<DownloadNuGet OutputFilename="$(NuGetExePath)" Condition=" '$(DownloadNuGetExe)' == 'true' AND !Exists('$(NuGetExePath)')" />
|
||||
</Target>
|
||||
|
||||
<Target Name="RestorePackages" DependsOnTargets="CheckPrerequisites">
|
||||
<Exec Command="$(RestoreCommand)"
|
||||
Condition="'$(OS)' != 'Windows_NT' And Exists('$(PackagesConfig)')" />
|
||||
|
||||
<Exec Command="$(RestoreCommand)"
|
||||
LogStandardErrorAsError="true"
|
||||
Condition="'$(OS)' == 'Windows_NT' And Exists('$(PackagesConfig)')" />
|
||||
</Target>
|
||||
|
||||
<Target Name="BuildPackage" DependsOnTargets="CheckPrerequisites">
|
||||
<Exec Command="$(BuildCommand)"
|
||||
Condition=" '$(OS)' != 'Windows_NT' " />
|
||||
|
||||
<Exec Command="$(BuildCommand)"
|
||||
LogStandardErrorAsError="true"
|
||||
Condition=" '$(OS)' == 'Windows_NT' " />
|
||||
</Target>
|
||||
|
||||
<UsingTask TaskName="DownloadNuGet" TaskFactory="CodeTaskFactory" AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.v4.0.dll">
|
||||
<ParameterGroup>
|
||||
<OutputFilename ParameterType="System.String" Required="true" />
|
||||
</ParameterGroup>
|
||||
<Task>
|
||||
<Reference Include="System.Core" />
|
||||
<Using Namespace="System" />
|
||||
<Using Namespace="System.IO" />
|
||||
<Using Namespace="System.Net" />
|
||||
<Using Namespace="Microsoft.Build.Framework" />
|
||||
<Using Namespace="Microsoft.Build.Utilities" />
|
||||
<Code Type="Fragment" Language="cs">
|
||||
<![CDATA[
|
||||
try {
|
||||
OutputFilename = Path.GetFullPath(OutputFilename);
|
||||
|
||||
Log.LogMessage("Downloading latest version of NuGet.exe...");
|
||||
WebClient webClient = new WebClient();
|
||||
webClient.DownloadFile("https://www.nuget.org/nuget.exe", OutputFilename);
|
||||
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex) {
|
||||
Log.LogErrorFromException(ex);
|
||||
return false;
|
||||
}
|
||||
]]>
|
||||
</Code>
|
||||
</Task>
|
||||
</UsingTask>
|
||||
</Project>
|
||||
21
GitVersion.yml
Normal file
21
GitVersion.yml
Normal file
@@ -0,0 +1,21 @@
|
||||
assembly-informational-format: '{NuGetVersion}'
|
||||
mode: ContinuousDeployment
|
||||
branches:
|
||||
master:
|
||||
tag: rc
|
||||
increment: Minor
|
||||
feature:
|
||||
regex: features?[/-]
|
||||
tag: rc-{BranchName}
|
||||
increment: Minor
|
||||
pull-request:
|
||||
regex: (pull|pull\-requests|pr)[/-]
|
||||
tag: rc-pr-{BranchName}
|
||||
increment: Minor
|
||||
hotfix:
|
||||
regex: hotfix(es)?[/-]
|
||||
tag: rc
|
||||
increment: Patch
|
||||
develop:
|
||||
regex: dev(elop)?(ment)?$
|
||||
tag: b
|
||||
@@ -1,12 +0,0 @@
|
||||
@echo off
|
||||
set /p version="Version: "
|
||||
msbuild S7.Net\S7.Net.csproj /P:Configuration=Release
|
||||
rmdir /S /Q nuget-pack\lib
|
||||
xcopy S7.Net\bin\Release\S7.Net.dll nuget-pack\lib\net35\ /Y
|
||||
xcopy S7.Net\bin\Release\S7.Net.xml nuget-pack\lib\net35\ /Y
|
||||
xcopy S7.Net\bin\Release\S7.Net.dll nuget-pack\lib\net40\ /Y
|
||||
xcopy S7.Net\bin\Release\S7.Net.xml nuget-pack\lib\net40\ /Y
|
||||
xcopy S7.Net\bin\Release\S7.Net.dll nuget-pack\lib\net45\ /Y
|
||||
xcopy S7.Net\bin\Release\S7.Net.xml nuget-pack\lib\net45\ /Y
|
||||
.nuget\nuget pack nuget-pack\S7.Net.nuspec -Version %version%
|
||||
pause
|
||||
16
README.md
16
README.md
@@ -12,18 +12,17 @@ to my request for committing code, I decided to pick up where he left off here o
|
||||
## Documentation
|
||||
Check the Wiki and feel free to edit it: https://github.com/killnine/s7netplus/wiki
|
||||
|
||||
S7.Net Plus has a [User Manual](https://github.com/killnine/s7netplus/blob/master/Documentation/Documentation.pdf), check it out.
|
||||
|
||||
## Supported PLC
|
||||
|
||||
+ Compatible S7 PLC (S7-200, S7-300, S7-400, S7-1200, S7-1500)
|
||||
|
||||
## Target framework
|
||||
+ .NET Framework 3.5 or higher
|
||||
+ Universal Windows Application (.Net Core) - see S7.UniversalWindowsApp.sln
|
||||
## Supported frameworks
|
||||
+ .NET Framework 4.5.2 and higher
|
||||
+ .NET Standard 1.3 (.NET Core 1.0, UWP 10.0, Xamarin, ...)
|
||||
+ .NET Standard 2.0 (.NET Core 2.0, .NET Framework 4.6.1)
|
||||
|
||||
## Compile
|
||||
You need at least Visual Studio 2015 (you can download the Community Edition for free).
|
||||
You need at least Visual Studio 2017 (you can download the Community Edition for free).
|
||||
|
||||
## Nuget
|
||||
|
||||
@@ -35,6 +34,5 @@ PM> Install-Package S7netplus
|
||||
|
||||
## Running the tests
|
||||
|
||||
Unit tests use Snap7 server, so port 102 must be not in use.
|
||||
If you have Siemens Step7 installed, the service s7oiehsx64 is stopped when running unit tests.
|
||||
You have to restart the service manually if you need it.
|
||||
Unit tests use Snap7 server.
|
||||
On Windows, the DLL is included with the test project. On other platforms, Snap7 must be installed manually before running tests.
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("S7.Net.Core")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("Microsoft")]
|
||||
[assembly: AssemblyProduct("S7.Net.Core")]
|
||||
[assembly: AssemblyCopyright("Copyright © Microsoft 2016")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
||||
[assembly: ComVisible(false)]
|
||||
@@ -1,33 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
This file contains Runtime Directives, specifications about types your application accesses
|
||||
through reflection and other dynamic code patterns. Runtime Directives are used to control the
|
||||
.NET Native optimizer and ensure that it does not remove code accessed by your library. If your
|
||||
library does not do any reflection, then you generally do not need to edit this file. However,
|
||||
if your library reflects over types, especially types passed to it or derived from its types,
|
||||
then you should write Runtime Directives.
|
||||
|
||||
The most common use of reflection in libraries is to discover information about types passed
|
||||
to the library. Runtime Directives have three ways to express requirements on types passed to
|
||||
your library.
|
||||
|
||||
1. Parameter, GenericParameter, TypeParameter, TypeEnumerableParameter
|
||||
Use these directives to reflect over types passed as a parameter.
|
||||
|
||||
2. SubTypes
|
||||
Use a SubTypes directive to reflect over types derived from another type.
|
||||
|
||||
3. AttributeImplies
|
||||
Use an AttributeImplies directive to indicate that your library needs to reflect over
|
||||
types or methods decorated with an attribute.
|
||||
|
||||
For more information on writing Runtime Directives for libraries, please visit
|
||||
http://go.microsoft.com/fwlink/?LinkID=391919
|
||||
-->
|
||||
<Directives xmlns="http://schemas.microsoft.com/netfx/2013/01/metadata">
|
||||
<Library Name="S7.Net.Core">
|
||||
|
||||
<!-- add directives for your library here -->
|
||||
|
||||
</Library>
|
||||
</Directives>
|
||||
@@ -1,176 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{CBFF80E8-3D3D-4656-A27C-A65EA5774536}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>S7.Net.Core</RootNamespace>
|
||||
<AssemblyName>S7.Net.Core</AssemblyName>
|
||||
<DefaultLanguage>en-US</DefaultLanguage>
|
||||
<TargetPlatformIdentifier>UAP</TargetPlatformIdentifier>
|
||||
<TargetPlatformVersion>10.0.10586.0</TargetPlatformVersion>
|
||||
<TargetPlatformMinVersion>10.0.10240.0</TargetPlatformMinVersion>
|
||||
<MinimumVisualStudioVersion>14</MinimumVisualStudioVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<ProjectTypeGuids>{A5A43C5B-DE2A-4C0C-9213-0A381AF9435A};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<PlatformTarget>ARM</PlatformTarget>
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<PlatformTarget>ARM</PlatformTarget>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
|
||||
<PlatformTarget>x86</PlatformTarget>
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<OutputPath>bin\x86\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
|
||||
<NoWarn>;2008</NoWarn>
|
||||
<DebugType>full</DebugType>
|
||||
<PlatformTarget>x86</PlatformTarget>
|
||||
<UseVSHostingProcess>false</UseVSHostingProcess>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
|
||||
<PlatformTarget>x86</PlatformTarget>
|
||||
<OutputPath>bin\x86\Release\</OutputPath>
|
||||
<DefineConstants>TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
|
||||
<Optimize>true</Optimize>
|
||||
<NoWarn>;2008</NoWarn>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<PlatformTarget>x86</PlatformTarget>
|
||||
<UseVSHostingProcess>false</UseVSHostingProcess>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|ARM'">
|
||||
<PlatformTarget>ARM</PlatformTarget>
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<OutputPath>bin\ARM\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
|
||||
<NoWarn>;2008</NoWarn>
|
||||
<DebugType>full</DebugType>
|
||||
<PlatformTarget>ARM</PlatformTarget>
|
||||
<UseVSHostingProcess>false</UseVSHostingProcess>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|ARM'">
|
||||
<PlatformTarget>ARM</PlatformTarget>
|
||||
<OutputPath>bin\ARM\Release\</OutputPath>
|
||||
<DefineConstants>TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
|
||||
<Optimize>true</Optimize>
|
||||
<NoWarn>;2008</NoWarn>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<PlatformTarget>ARM</PlatformTarget>
|
||||
<UseVSHostingProcess>false</UseVSHostingProcess>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<OutputPath>bin\x64\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
|
||||
<NoWarn>;2008</NoWarn>
|
||||
<DebugType>full</DebugType>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<UseVSHostingProcess>false</UseVSHostingProcess>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<OutputPath>bin\x64\Release\</OutputPath>
|
||||
<DefineConstants>TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
|
||||
<Optimize>true</Optimize>
|
||||
<NoWarn>;2008</NoWarn>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<UseVSHostingProcess>false</UseVSHostingProcess>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<!-- A reference to the entire .Net Framework and Windows SDK are automatically included -->
|
||||
<None Include="project.json" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="..\S7.Net\Conversion.cs">
|
||||
<Link>Conversion.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\S7.Net\Enums.cs">
|
||||
<Link>Enums.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\S7.Net\PLC.cs">
|
||||
<Link>PLC.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\S7.Net\Types\Boolean.cs">
|
||||
<Link>Types\Boolean.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\S7.Net\Types\Byte.cs">
|
||||
<Link>Types\Byte.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\S7.Net\Types\ByteArray.cs">
|
||||
<Link>Types\ByteArray.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\S7.Net\Types\Class.cs">
|
||||
<Link>Types\Class.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\S7.Net\Types\Counter.cs">
|
||||
<Link>Types\Counter.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\S7.Net\Types\DataItem.cs">
|
||||
<Link>Types\DataItem.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\S7.Net\Types\DInt.cs">
|
||||
<Link>Types\DInt.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\S7.Net\Types\Double.cs">
|
||||
<Link>Types\Double.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\S7.Net\Types\DWord.cs">
|
||||
<Link>Types\DWord.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\S7.Net\Types\Int.cs">
|
||||
<Link>Types\Int.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\S7.Net\Types\String.cs">
|
||||
<Link>Types\String.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\S7.Net\Types\Struct.cs">
|
||||
<Link>Types\Struct.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\S7.Net\Types\Timer.cs">
|
||||
<Link>Types\Timer.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\S7.Net\Types\Word.cs">
|
||||
<Link>Types\Word.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="SocketClient.cs" />
|
||||
<EmbeddedResource Include="Properties\S7.Net.Core.rd.xml" />
|
||||
</ItemGroup>
|
||||
<PropertyGroup Condition=" '$(VisualStudioVersion)' == '' or '$(VisualStudioVersion)' < '14.0' ">
|
||||
<VisualStudioVersion>14.0</VisualStudioVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(MSBuildExtensionsPath)\Microsoft\WindowsXaml\v$(VisualStudioVersion)\Microsoft.Windows.UI.Xaml.CSharp.targets" />
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
<Target Name="BeforeBuild">
|
||||
</Target>
|
||||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
</Project>
|
||||
@@ -1,481 +0,0 @@
|
||||
using System;
|
||||
using System.Net.Sockets;
|
||||
using System.Threading;
|
||||
using System.Net;
|
||||
|
||||
namespace S7.Net
|
||||
{
|
||||
/// <summary>
|
||||
/// This class encapsulate System.Net.Sockets.Socket class of .Net core, so we can use the same methods of the standard Socket class inside the S7.Net sources.
|
||||
/// </summary>
|
||||
internal class Socket
|
||||
{
|
||||
|
||||
public bool Connected
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_socket == null)
|
||||
return false;
|
||||
|
||||
return _socket.Connected;
|
||||
}
|
||||
}
|
||||
|
||||
public SocketError LastSocketError { get; private set; }
|
||||
|
||||
public Socket(AddressFamily addressFamily, SocketType socketType, ProtocolType protocolType)
|
||||
{
|
||||
_socket = new System.Net.Sockets.Socket(addressFamily, socketType, protocolType);
|
||||
}
|
||||
|
||||
public void Connect(IPEndPoint server)
|
||||
{
|
||||
if (Connected)
|
||||
return;
|
||||
|
||||
LastSocketError = SocketError.NotConnected;
|
||||
|
||||
var socketEventArg = new SocketAsyncEventArgs();
|
||||
|
||||
socketEventArg.RemoteEndPoint = server;
|
||||
|
||||
var completedEvent = new EventHandler<SocketAsyncEventArgs>(delegate (object s, SocketAsyncEventArgs e)
|
||||
{
|
||||
LastSocketError = e.SocketError;
|
||||
_clientDone.Set();
|
||||
});
|
||||
|
||||
socketEventArg.Completed += completedEvent;
|
||||
|
||||
_clientDone.Reset();
|
||||
|
||||
LastSocketError = SocketError.TimedOut;
|
||||
|
||||
_socket.ConnectAsync(socketEventArg);
|
||||
|
||||
_clientDone.WaitOne(TIMEOUT_MILLISECONDS);
|
||||
|
||||
socketEventArg.Completed -= completedEvent;
|
||||
}
|
||||
|
||||
public int Send(byte[] buffer, int size, SocketFlags socketFlag)
|
||||
{
|
||||
var response = 0;
|
||||
|
||||
if (_socket != null)
|
||||
{
|
||||
var socketEventArg = new SocketAsyncEventArgs();
|
||||
|
||||
socketEventArg.RemoteEndPoint = _socket.RemoteEndPoint;
|
||||
socketEventArg.UserToken = null;
|
||||
|
||||
var completedEvent = new EventHandler<SocketAsyncEventArgs>(delegate (object s, SocketAsyncEventArgs e)
|
||||
{
|
||||
LastSocketError = e.SocketError;
|
||||
|
||||
if (e.SocketError == SocketError.Success)
|
||||
response = e.BytesTransferred;
|
||||
|
||||
_clientDone.Set();
|
||||
});
|
||||
|
||||
socketEventArg.Completed += completedEvent;
|
||||
|
||||
socketEventArg.SetBuffer(buffer, 0, size);
|
||||
|
||||
_clientDone.Reset();
|
||||
|
||||
LastSocketError = SocketError.TimedOut;
|
||||
|
||||
_socket.SendAsync(socketEventArg);
|
||||
|
||||
_clientDone.WaitOne(_sendTimeout);
|
||||
|
||||
socketEventArg.Completed -= completedEvent;
|
||||
}
|
||||
else
|
||||
{
|
||||
LastSocketError = SocketError.NotInitialized;
|
||||
}
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
public int Receive(byte[] buffer, int size, SocketFlags socketFlag)
|
||||
{
|
||||
var response = 0;
|
||||
|
||||
if (_socket != null)
|
||||
{
|
||||
var socketEventArg = new SocketAsyncEventArgs();
|
||||
|
||||
socketEventArg.RemoteEndPoint = _socket.RemoteEndPoint;
|
||||
socketEventArg.SetBuffer(buffer, 0, size);
|
||||
|
||||
var completedEvent = new EventHandler<SocketAsyncEventArgs>(delegate (object s, SocketAsyncEventArgs e)
|
||||
{
|
||||
LastSocketError = e.SocketError;
|
||||
|
||||
if (e.SocketError == SocketError.Success)
|
||||
response = e.BytesTransferred;
|
||||
|
||||
_clientDone.Set();
|
||||
});
|
||||
|
||||
socketEventArg.Completed += completedEvent;
|
||||
|
||||
_clientDone.Reset();
|
||||
|
||||
LastSocketError = SocketError.TimedOut;
|
||||
|
||||
_socket.ReceiveAsync(socketEventArg);
|
||||
|
||||
_clientDone.WaitOne(_receiveTimeout);
|
||||
|
||||
socketEventArg.Completed -= completedEvent;
|
||||
}
|
||||
else
|
||||
{
|
||||
LastSocketError = SocketError.NotInitialized;
|
||||
}
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
public void Shutdown(SocketShutdown how)
|
||||
{
|
||||
_socket.Shutdown(how);
|
||||
}
|
||||
|
||||
public void Close()
|
||||
{
|
||||
if (_socket != null)
|
||||
{
|
||||
_socket.Dispose();
|
||||
_socket = null;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Summary:
|
||||
// Sets the specified System.Net.Sockets.Socket option to the specified integer
|
||||
// value.
|
||||
//
|
||||
// Parameters:
|
||||
// optionLevel:
|
||||
// One of the System.Net.Sockets.SocketOptionLevel values.
|
||||
//
|
||||
// optionName:
|
||||
// One of the System.Net.Sockets.SocketOptionName values.
|
||||
//
|
||||
// optionValue:
|
||||
// A value of the option.
|
||||
//
|
||||
// Exceptions:
|
||||
// T:System.Net.Sockets.SocketException:
|
||||
// An error occurred when attempting to access the socket. See the Remarks section
|
||||
// for more information.
|
||||
//
|
||||
// T:System.ObjectDisposedException:
|
||||
// The System.Net.Sockets.Socket has been closed.
|
||||
public void SetSocketOption(SocketOptionLevel optionLevel, SocketOptionName optionName, int optionValue)
|
||||
{
|
||||
switch (optionName)
|
||||
{
|
||||
case SocketOptionName.ReceiveTimeout:
|
||||
_receiveTimeout = optionValue;
|
||||
break;
|
||||
|
||||
case SocketOptionName.SendTimeout:
|
||||
_sendTimeout = optionValue;
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new NotImplementedException("SetSocketOption option not implemented");
|
||||
}
|
||||
}
|
||||
|
||||
private System.Net.Sockets.Socket _socket = null;
|
||||
private int _receiveTimeout = TIMEOUT_MILLISECONDS;
|
||||
private int _sendTimeout = TIMEOUT_MILLISECONDS;
|
||||
|
||||
private readonly static ManualResetEvent _clientDone =
|
||||
new ManualResetEvent(false);
|
||||
|
||||
private const int TIMEOUT_MILLISECONDS = 1000;
|
||||
|
||||
}
|
||||
|
||||
//
|
||||
// Summary:
|
||||
// Specifies socket send and receive behaviors.
|
||||
[Flags]
|
||||
public enum SocketFlags
|
||||
{
|
||||
//
|
||||
// Summary:
|
||||
// Use no flags for this call.
|
||||
None = 0,
|
||||
////
|
||||
//// Summary:
|
||||
//// Process out-of-band data.
|
||||
//OutOfBand = 1,
|
||||
////
|
||||
//// Summary:
|
||||
//// Peek at the incoming message.
|
||||
//Peek = 2,
|
||||
////
|
||||
//// Summary:
|
||||
//// Send without using routing tables.
|
||||
//DontRoute = 4,
|
||||
////
|
||||
//// Summary:
|
||||
//// Provides a standard value for the number of WSABUF structures that are used to
|
||||
//// send and receive data.
|
||||
//MaxIOVectorLength = 16,
|
||||
////
|
||||
//// Summary:
|
||||
//// The message was too large to fit into the specified buffer and was truncated.
|
||||
//Truncated = 256,
|
||||
////
|
||||
//// Summary:
|
||||
//// Indicates that the control data did not fit into an internal 64-KB buffer and
|
||||
//// was truncated.
|
||||
//ControlDataTruncated = 512,
|
||||
////
|
||||
//// Summary:
|
||||
//// Indicates a broadcast packet.
|
||||
//Broadcast = 1024,
|
||||
////
|
||||
//// Summary:
|
||||
//// Indicates a multicast packet.
|
||||
//Multicast = 2048,
|
||||
////
|
||||
//// Summary:
|
||||
//// Partial send or receive for message.
|
||||
//Partial = 32768
|
||||
}
|
||||
|
||||
//
|
||||
// Summary:
|
||||
// Defines socket option levels for the System.Net.Sockets.Socket.SetSocketOption(System.Net.Sockets.SocketOptionLevel,System.Net.Sockets.SocketOptionName,System.Int32)
|
||||
// and System.Net.Sockets.Socket.GetSocketOption(System.Net.Sockets.SocketOptionLevel,System.Net.Sockets.SocketOptionName)
|
||||
// methods.
|
||||
public enum SocketOptionLevel
|
||||
{
|
||||
//
|
||||
// Summary:
|
||||
// System.Net.Sockets.Socket options apply only to IP sockets.
|
||||
IP = 0,
|
||||
//
|
||||
// Summary:
|
||||
// System.Net.Sockets.Socket options apply only to TCP sockets.
|
||||
Tcp = 6,
|
||||
//
|
||||
// Summary:
|
||||
// System.Net.Sockets.Socket options apply only to UDP sockets.
|
||||
Udp = 17,
|
||||
//
|
||||
// Summary:
|
||||
// System.Net.Sockets.Socket options apply only to IPv6 sockets.
|
||||
IPv6 = 41,
|
||||
//
|
||||
// Summary:
|
||||
// System.Net.Sockets.Socket options apply to all sockets.
|
||||
Socket = 65535
|
||||
}
|
||||
|
||||
//
|
||||
// Summary:
|
||||
// Defines configuration option names.
|
||||
public enum SocketOptionName
|
||||
{
|
||||
//
|
||||
// Summary:
|
||||
// Close the socket gracefully without lingering.
|
||||
DontLinger = -129,
|
||||
//
|
||||
// Summary:
|
||||
// Enables a socket to be bound for exclusive access.
|
||||
ExclusiveAddressUse = -5,
|
||||
//
|
||||
// Summary:
|
||||
// Record debugging information.
|
||||
Debug = 1,
|
||||
//
|
||||
// Summary:
|
||||
// Specifies the IP options to be inserted into outgoing datagrams.
|
||||
IPOptions = 1,
|
||||
//
|
||||
// Summary:
|
||||
// Disables the Nagle algorithm for send coalescing.
|
||||
NoDelay = 1,
|
||||
//
|
||||
// Summary:
|
||||
// Send UDP datagrams with checksum set to zero.
|
||||
NoChecksum = 1,
|
||||
//
|
||||
// Summary:
|
||||
// The socket is listening.
|
||||
AcceptConnection = 2,
|
||||
//
|
||||
// Summary:
|
||||
// Indicates that the application provides the IP header for outgoing datagrams.
|
||||
HeaderIncluded = 2,
|
||||
//
|
||||
// Summary:
|
||||
// Use urgent data as defined in RFC-1222. This option can be set only once; after
|
||||
// it is set, it cannot be turned off.
|
||||
BsdUrgent = 2,
|
||||
//
|
||||
// Summary:
|
||||
// Use expedited data as defined in RFC-1222. This option can be set only once;
|
||||
// after it is set, it cannot be turned off.
|
||||
Expedited = 2,
|
||||
//
|
||||
// Summary:
|
||||
// Change the IP header type of the service field.
|
||||
TypeOfService = 3,
|
||||
//
|
||||
// Summary:
|
||||
// Allows the socket to be bound to an address that is already in use.
|
||||
ReuseAddress = 4,
|
||||
//
|
||||
// Summary:
|
||||
// Set the IP header Time-to-Live field.
|
||||
IpTimeToLive = 4,
|
||||
//
|
||||
// Summary:
|
||||
// Use keep-alives.
|
||||
KeepAlive = 8,
|
||||
//
|
||||
// Summary:
|
||||
// Set the interface for outgoing multicast packets.
|
||||
MulticastInterface = 9,
|
||||
//
|
||||
// Summary:
|
||||
// An IP multicast Time to Live.
|
||||
MulticastTimeToLive = 10,
|
||||
//
|
||||
// Summary:
|
||||
// An IP multicast loopback.
|
||||
MulticastLoopback = 11,
|
||||
//
|
||||
// Summary:
|
||||
// Add an IP group membership.
|
||||
AddMembership = 12,
|
||||
//
|
||||
// Summary:
|
||||
// Drop an IP group membership.
|
||||
DropMembership = 13,
|
||||
//
|
||||
// Summary:
|
||||
// Do not fragment IP datagrams.
|
||||
DontFragment = 14,
|
||||
//
|
||||
// Summary:
|
||||
// Join a source group.
|
||||
AddSourceMembership = 15,
|
||||
//
|
||||
// Summary:
|
||||
// Do not route; send the packet directly to the interface addresses.
|
||||
DontRoute = 16,
|
||||
//
|
||||
// Summary:
|
||||
// Drop a source group.
|
||||
DropSourceMembership = 16,
|
||||
//
|
||||
// Summary:
|
||||
// Block data from a source.
|
||||
BlockSource = 17,
|
||||
//
|
||||
// Summary:
|
||||
// Unblock a previously blocked source.
|
||||
UnblockSource = 18,
|
||||
//
|
||||
// Summary:
|
||||
// Return information about received packets.
|
||||
PacketInformation = 19,
|
||||
//
|
||||
// Summary:
|
||||
// Set or get the UDP checksum coverage.
|
||||
ChecksumCoverage = 20,
|
||||
//
|
||||
// Summary:
|
||||
// Specifies the maximum number of router hops for an Internet Protocol version
|
||||
// 6 (IPv6) packet. This is similar to Time to Live (TTL) for Internet Protocol
|
||||
// version 4.
|
||||
HopLimit = 21,
|
||||
//
|
||||
// Summary:
|
||||
// Permit sending broadcast messages on the socket.
|
||||
Broadcast = 32,
|
||||
//
|
||||
// Summary:
|
||||
// Bypass hardware when possible.
|
||||
UseLoopback = 64,
|
||||
//
|
||||
// Summary:
|
||||
// Linger on close if unsent data is present.
|
||||
Linger = 128,
|
||||
//
|
||||
// Summary:
|
||||
// Receives out-of-band data in the normal data stream.
|
||||
OutOfBandInline = 256,
|
||||
//
|
||||
// Summary:
|
||||
// Specifies the total per-socket buffer space reserved for sends. This is unrelated
|
||||
// to the maximum message size or the size of a TCP window.
|
||||
SendBuffer = 4097,
|
||||
//
|
||||
// Summary:
|
||||
// Specifies the total per-socket buffer space reserved for receives. This is unrelated
|
||||
// to the maximum message size or the size of a TCP window.
|
||||
ReceiveBuffer = 4098,
|
||||
//
|
||||
// Summary:
|
||||
// Specifies the low water mark for Overload:System.Net.Sockets.Socket.Send operations.
|
||||
SendLowWater = 4099,
|
||||
//
|
||||
// Summary:
|
||||
// Specifies the low water mark for Overload:System.Net.Sockets.Socket.Receive operations.
|
||||
ReceiveLowWater = 4100,
|
||||
//
|
||||
// Summary:
|
||||
// Send a time-out. This option applies only to synchronous methods; it has no effect
|
||||
// on asynchronous methods such as the System.Net.Sockets.Socket.BeginSend(System.Byte[],System.Int32,System.Int32,System.Net.Sockets.SocketFlags,System.AsyncCallback,System.Object)
|
||||
// method.
|
||||
SendTimeout = 4101,
|
||||
//
|
||||
// Summary:
|
||||
// Receive a time-out. This option applies only to synchronous methods; it has no
|
||||
// effect on asynchronous methods such as the System.Net.Sockets.Socket.BeginSend(System.Byte[],System.Int32,System.Int32,System.Net.Sockets.SocketFlags,System.AsyncCallback,System.Object)
|
||||
// method.
|
||||
ReceiveTimeout = 4102,
|
||||
//
|
||||
// Summary:
|
||||
// Get the error status and clear.
|
||||
Error = 4103,
|
||||
//
|
||||
// Summary:
|
||||
// Get the socket type.
|
||||
Type = 4104,
|
||||
//
|
||||
// Summary:
|
||||
// Updates an accepted socket's properties by using those of an existing socket.
|
||||
// This is equivalent to using the Winsock2 SO_UPDATE_ACCEPT_CONTEXT socket option
|
||||
// and is supported only on connection-oriented sockets.
|
||||
UpdateAcceptContext = 28683,
|
||||
//
|
||||
// Summary:
|
||||
// Updates a connected socket's properties by using those of an existing socket.
|
||||
// This is equivalent to using the Winsock2 SO_UPDATE_CONNECT_CONTEXT socket option
|
||||
// and is supported only on connection-oriented sockets.
|
||||
UpdateConnectContext = 28688,
|
||||
//
|
||||
// Summary:
|
||||
// Not supported; will throw a System.Net.Sockets.SocketException if used.
|
||||
MaxConnections = int.MaxValue
|
||||
}
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
{
|
||||
"dependencies": {
|
||||
"Microsoft.NETCore.UniversalWindowsPlatform": "5.0.0"
|
||||
},
|
||||
"frameworks": {
|
||||
"uap10.0": {}
|
||||
},
|
||||
"runtimes": {
|
||||
"win10-arm": {},
|
||||
"win10-arm-aot": {},
|
||||
"win10-x86": {},
|
||||
"win10-x86-aot": {},
|
||||
"win10-x64": {},
|
||||
"win10-x64-aot": {}
|
||||
}
|
||||
}
|
||||
82
S7.Net.UnitTest/ConnectionRequestTest.cs
Normal file
82
S7.Net.UnitTest/ConnectionRequestTest.cs
Normal file
@@ -0,0 +1,82 @@
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using S7.Net.Protocol;
|
||||
|
||||
namespace S7.Net.UnitTest
|
||||
{
|
||||
[TestClass]
|
||||
public class ConnectionRequestTest
|
||||
{
|
||||
[TestMethod]
|
||||
public void Test_ConnectionRequest_S7_200()
|
||||
{
|
||||
CollectionAssert.AreEqual(MakeConnectionRequest(16, 0, 16, 0),
|
||||
ConnectionRequest.GetCOTPConnectionRequest(CpuType.S7200, 0, 0));
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void Test_ConnectionRequest_S7_300()
|
||||
{
|
||||
CollectionAssert.AreEqual(MakeConnectionRequest(1, 0, 3, 0),
|
||||
ConnectionRequest.GetCOTPConnectionRequest(CpuType.S7300, 0, 0));
|
||||
CollectionAssert.AreEqual(MakeConnectionRequest(1, 0, 3, 1),
|
||||
ConnectionRequest.GetCOTPConnectionRequest(CpuType.S7300, 0, 1));
|
||||
CollectionAssert.AreEqual(MakeConnectionRequest(1, 0, 3, 33),
|
||||
ConnectionRequest.GetCOTPConnectionRequest(CpuType.S7300, 1, 1));
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void Test_ConnectionRequest_S7_400()
|
||||
{
|
||||
CollectionAssert.AreEqual(MakeConnectionRequest(1, 0, 3, 0),
|
||||
ConnectionRequest.GetCOTPConnectionRequest(CpuType.S7400, 0, 0));
|
||||
CollectionAssert.AreEqual(MakeConnectionRequest(1, 0, 3, 1),
|
||||
ConnectionRequest.GetCOTPConnectionRequest(CpuType.S7400, 0, 1));
|
||||
CollectionAssert.AreEqual(MakeConnectionRequest(1, 0, 3, 33),
|
||||
ConnectionRequest.GetCOTPConnectionRequest(CpuType.S7400, 1, 1));
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void Test_ConnectionRequest_S7_1200()
|
||||
{
|
||||
CollectionAssert.AreEqual(MakeConnectionRequest(1, 0, 3, 0),
|
||||
ConnectionRequest.GetCOTPConnectionRequest(CpuType.S71200, 0, 0));
|
||||
CollectionAssert.AreEqual(MakeConnectionRequest(1, 0, 3, 1),
|
||||
ConnectionRequest.GetCOTPConnectionRequest(CpuType.S71200, 0, 1));
|
||||
CollectionAssert.AreEqual(MakeConnectionRequest(1, 0, 3, 33),
|
||||
ConnectionRequest.GetCOTPConnectionRequest(CpuType.S71200, 1, 1));
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void Test_ConnectionRequest_S7_1500()
|
||||
{
|
||||
CollectionAssert.AreEqual(MakeConnectionRequest(0x10, 0x2, 3, 0),
|
||||
ConnectionRequest.GetCOTPConnectionRequest(CpuType.S71500, 0, 0));
|
||||
CollectionAssert.AreEqual(MakeConnectionRequest(0x10, 0x2, 3, 1),
|
||||
ConnectionRequest.GetCOTPConnectionRequest(CpuType.S71500, 0, 1));
|
||||
CollectionAssert.AreEqual(MakeConnectionRequest(0x10, 0x2, 3, 33),
|
||||
ConnectionRequest.GetCOTPConnectionRequest(CpuType.S71500, 1, 1));
|
||||
}
|
||||
|
||||
private static byte[] MakeConnectionRequest(byte sourceTsap1, byte sourceTsap2, byte destTsap1, byte destTsap2)
|
||||
{
|
||||
return new byte[]
|
||||
{
|
||||
3, 0, 0, 22, //TPKT
|
||||
17, //COTP Header Length
|
||||
224, //Connect Request
|
||||
0, 0, //Destination Reference
|
||||
0, 46, //Source Reference
|
||||
0, //Flags
|
||||
193, //Parameter Code (src-tasp)
|
||||
2, //Parameter Length
|
||||
sourceTsap1, sourceTsap2, //Source TASP
|
||||
194, //Parameter Code (dst-tasp)
|
||||
2, //Parameter Length
|
||||
destTsap1, destTsap2, //Destination TASP
|
||||
192, //Parameter Code (tpdu-size)
|
||||
1, //Parameter Length
|
||||
10 //TPDU Size (2^11 = 2048)
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,9 +6,10 @@ namespace S7.Net.UnitTest.Helpers
|
||||
class S7TestServer
|
||||
{
|
||||
static S7Server Server;
|
||||
static private byte[] DB1 = new byte[512]; // Our DB1
|
||||
static private byte[] DB1 = new byte[1024]; // Our DB1
|
||||
static private byte[] DB2 = new byte[64000]; // Our DB2
|
||||
static private byte[] DB3 = new byte[1024]; // Our DB3
|
||||
static private byte[] DB4 = new byte[6] { 3, 128, 1, 0, 197, 104 }; // Our DB4
|
||||
|
||||
private static S7Server.TSrvCallback TheEventCallBack; // <== Static var containig the callback
|
||||
private static S7Server.TSrvCallback TheReadCallBack; // <== Static var containig the callback
|
||||
@@ -28,7 +29,7 @@ namespace S7.Net.UnitTest.Helpers
|
||||
Console.WriteLine(Server.EventText(ref Event));
|
||||
}
|
||||
|
||||
public static void Start()
|
||||
public static void Start(short port)
|
||||
{
|
||||
Server = new S7Server();
|
||||
// Share some resources with our virtual PLC
|
||||
@@ -36,9 +37,10 @@ namespace S7.Net.UnitTest.Helpers
|
||||
1, // Its number is 1 (DB1)
|
||||
DB1, // Our buffer for DB1
|
||||
DB1.Length); // Its size
|
||||
// Do the same for DB2 and DB3
|
||||
// Do the same for DB2, DB3, and DB4
|
||||
Server.RegisterArea(S7Server.srvAreaDB, 2, DB2, DB2.Length);
|
||||
Server.RegisterArea(S7Server.srvAreaDB, 3, DB3, DB3.Length);
|
||||
Server.RegisterArea(S7Server.srvAreaDB, 4, DB4, DB4.Length);
|
||||
|
||||
// Exclude read event to avoid the double report
|
||||
// Set the callbacks (using the static var to avoid the garbage collect)
|
||||
@@ -57,7 +59,14 @@ namespace S7.Net.UnitTest.Helpers
|
||||
// Start the server onto the default adapter.
|
||||
// To select an adapter we have to use Server->StartTo("192.168.x.y").
|
||||
// Start() is the same of StartTo("0.0.0.0");
|
||||
|
||||
Server.SetParam(S7Consts.p_u16_LocalPort, ref port);
|
||||
|
||||
int Error = Server.Start();
|
||||
if (Error != 0)
|
||||
{
|
||||
throw new Exception($"Error starting Snap7 server: {Server.ErrorText(Error)}");
|
||||
}
|
||||
//if (Error == 0)
|
||||
//{
|
||||
// // Now the server is running ... wait a key to terminate
|
||||
|
||||
@@ -35,16 +35,21 @@ namespace S7.Net.UnitTest.Helpers
|
||||
/// <summary>
|
||||
/// DB1.DBD4
|
||||
/// </summary>
|
||||
public double RealVariable { get; set; }
|
||||
public double LRealVariable { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// DB1.DBD8
|
||||
/// </summary>
|
||||
public int DIntVariable { get; set; }
|
||||
public float RealVariable { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// DB1.DBD12
|
||||
/// </summary>
|
||||
public int DIntVariable { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// DB1.DBD16
|
||||
/// </summary>
|
||||
public ushort DWordVariable { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,10 +15,12 @@ namespace S7.UnitTest.Helpers
|
||||
public ushort[] UShorts { get; set; } = new ushort[2];
|
||||
public int[] Ints { get; set; } = new int[2];
|
||||
public double[] Doubles { get; set; } = new double[2];
|
||||
public float[] Singles { get; set; } = new float[2];
|
||||
|
||||
public short Short { get; set; }
|
||||
public ushort UShort { get; set; }
|
||||
public int Int { get; set; }
|
||||
public double Double { get; set; }
|
||||
public float Single { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
51
S7.Net.UnitTest/Helpers/TestClassWithNestedClass.cs
Normal file
51
S7.Net.UnitTest/Helpers/TestClassWithNestedClass.cs
Normal file
@@ -0,0 +1,51 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace S7.Net.UnitTest.Helpers
|
||||
{
|
||||
class TestClassInnerWithBool
|
||||
{
|
||||
public bool BitVariable00 { get; set; }
|
||||
}
|
||||
|
||||
class TestClassInnerWithByte
|
||||
{
|
||||
public byte ByteVariable00 { get; set; }
|
||||
}
|
||||
|
||||
class TestClassInnerWithShort
|
||||
{
|
||||
public short ShortVarialbe00 { get; set; }
|
||||
}
|
||||
|
||||
class TestClassWithNestedClass
|
||||
{
|
||||
/// <summary>
|
||||
/// DB1.DBX0.0
|
||||
/// </summary>
|
||||
public bool BitVariable00 { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// DB1.DBX0.1
|
||||
/// </summary>
|
||||
public TestClassInnerWithBool BitVariable01 { get; set; } = new TestClassInnerWithBool();
|
||||
|
||||
/// <summary>
|
||||
/// DB1.DBB1.0
|
||||
/// </summary>
|
||||
public TestClassInnerWithByte ByteVariable02 { get; set; } = new TestClassInnerWithByte();
|
||||
|
||||
/// <summary>
|
||||
/// DB1.DBX2.0
|
||||
/// </summary>
|
||||
public bool BitVariable03 { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// DB1.DBW4
|
||||
/// </summary>
|
||||
public TestClassInnerWithShort ShortVariable04 { get; set; } = new TestClassInnerWithShort();
|
||||
}
|
||||
}
|
||||
12
S7.Net.UnitTest/Helpers/TestSmallClass.cs
Normal file
12
S7.Net.UnitTest/Helpers/TestSmallClass.cs
Normal file
@@ -0,0 +1,12 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace S7.UnitTest.Helpers
|
||||
{
|
||||
class TestSmallClass
|
||||
{
|
||||
public bool Bool1 { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
|
||||
using S7.Net.Types;
|
||||
|
||||
namespace S7.Net.UnitTest.Helpers
|
||||
{
|
||||
public struct TestStruct
|
||||
@@ -7,6 +8,7 @@ namespace S7.Net.UnitTest.Helpers
|
||||
/// DB1.DBX0.0
|
||||
/// </summary>
|
||||
public bool BitVariable00;
|
||||
|
||||
public bool BitVariable01;
|
||||
public bool BitVariable02;
|
||||
public bool BitVariable03;
|
||||
@@ -19,6 +21,7 @@ namespace S7.Net.UnitTest.Helpers
|
||||
/// DB1.DBX1.0
|
||||
/// </summary>
|
||||
public bool BitVariable10;
|
||||
|
||||
public bool BitVariable11;
|
||||
public bool BitVariable12;
|
||||
public bool BitVariable13;
|
||||
@@ -35,16 +38,33 @@ namespace S7.Net.UnitTest.Helpers
|
||||
/// <summary>
|
||||
/// DB1.DBD4
|
||||
/// </summary>
|
||||
public double RealVariable;
|
||||
public double LRealVariable;
|
||||
|
||||
/// <summary>
|
||||
/// DB1.DBD8
|
||||
/// </summary>
|
||||
public int DIntVariable;
|
||||
public float RealVariable;
|
||||
|
||||
/// <summary>
|
||||
/// DB1.DBD12
|
||||
/// </summary>
|
||||
public int DIntVariable;
|
||||
|
||||
/// <summary>
|
||||
/// DB1.DBD16
|
||||
/// </summary>
|
||||
public ushort DWordVariable;
|
||||
|
||||
/// <summary>
|
||||
/// DB1.DBX20.0
|
||||
/// </summary>
|
||||
[S7String(S7StringType.S7WString, 10)]
|
||||
public string WStringVariable;
|
||||
|
||||
/// <summary>
|
||||
/// DB1.DBX44.0
|
||||
/// </summary>
|
||||
[S7String(S7StringType.S7String, 10)]
|
||||
public string StringVariable;
|
||||
}
|
||||
}
|
||||
|
||||
156
S7.Net.UnitTest/PLCAddressParsingTests.cs
Normal file
156
S7.Net.UnitTest/PLCAddressParsingTests.cs
Normal file
@@ -0,0 +1,156 @@
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using S7.Net.Types;
|
||||
using System;
|
||||
|
||||
namespace S7.Net.UnitTest
|
||||
{
|
||||
[TestClass]
|
||||
public class PLCAddressParsingTests
|
||||
{
|
||||
[TestMethod]
|
||||
public void T01_ParseM2000_1()
|
||||
{
|
||||
DataItem dataItem = DataItem.FromAddress("M2000.1");
|
||||
|
||||
Assert.AreEqual(DataType.Memory, dataItem.DataType, "Wrong datatype for M2000.1");
|
||||
Assert.AreEqual(0, dataItem.DB, "Wrong dbnumber for M2000.1");
|
||||
Assert.AreEqual(VarType.Bit, dataItem.VarType, "Wrong vartype for M2000.1");
|
||||
Assert.AreEqual(2000, dataItem.StartByteAdr, "Wrong startbyte for M2000.1");
|
||||
Assert.AreEqual(1, dataItem.BitAdr, "Wrong bit for M2000.1");
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void T02_ParseMB200()
|
||||
{
|
||||
DataItem dataItem = DataItem.FromAddress("MB200");
|
||||
|
||||
Assert.AreEqual(DataType.Memory, dataItem.DataType, "Wrong datatype for MB200");
|
||||
Assert.AreEqual(0, dataItem.DB, "Wrong dbnumber for MB200");
|
||||
Assert.AreEqual(VarType.Byte, dataItem.VarType, "Wrong vartype for MB200");
|
||||
Assert.AreEqual(200, dataItem.StartByteAdr, "Wrong startbyte for MB200");
|
||||
Assert.AreEqual(0, dataItem.BitAdr, "Wrong bit for MB200");
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void T03_ParseMW200()
|
||||
{
|
||||
DataItem dataItem = DataItem.FromAddress("MW200");
|
||||
|
||||
Assert.AreEqual(DataType.Memory, dataItem.DataType, "Wrong datatype for MW200");
|
||||
Assert.AreEqual(0, dataItem.DB, "Wrong dbnumber for MW200");
|
||||
Assert.AreEqual(VarType.Word, dataItem.VarType, "Wrong vartype for MW200");
|
||||
Assert.AreEqual(200, dataItem.StartByteAdr, "Wrong startbyte for MW200");
|
||||
Assert.AreEqual(0, dataItem.BitAdr, "Wrong bit for MW200");
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void T04_ParseMD200()
|
||||
{
|
||||
DataItem dataItem = DataItem.FromAddress("MD200");
|
||||
|
||||
Assert.AreEqual(DataType.Memory, dataItem.DataType, "Wrong datatype for MD200");
|
||||
Assert.AreEqual(0, dataItem.DB, "Wrong dbnumber for MD200");
|
||||
Assert.AreEqual(VarType.DWord, dataItem.VarType, "Wrong vartype for MD200");
|
||||
Assert.AreEqual(200, dataItem.StartByteAdr, "Wrong startbyte for MD200");
|
||||
Assert.AreEqual(0, dataItem.BitAdr, "Wrong bit for MD200");
|
||||
}
|
||||
|
||||
|
||||
[TestMethod]
|
||||
public void T05_ParseI2000_1()
|
||||
{
|
||||
DataItem dataItem = DataItem.FromAddress("I2000.1");
|
||||
|
||||
Assert.AreEqual(DataType.Input, dataItem.DataType, "Wrong datatype for I2000.1");
|
||||
Assert.AreEqual(0, dataItem.DB, "Wrong dbnumber for I2000.1");
|
||||
Assert.AreEqual(VarType.Bit, dataItem.VarType, "Wrong vartype for I2000.1");
|
||||
Assert.AreEqual(2000, dataItem.StartByteAdr, "Wrong startbyte for I2000.1");
|
||||
Assert.AreEqual(1, dataItem.BitAdr, "Wrong bit for I2000.1");
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void T06_ParseIB200()
|
||||
{
|
||||
DataItem dataItem = DataItem.FromAddress("IB200");
|
||||
|
||||
Assert.AreEqual(DataType.Input, dataItem.DataType, "Wrong datatype for IB200");
|
||||
Assert.AreEqual(0, dataItem.DB, "Wrong dbnumber for IB200");
|
||||
Assert.AreEqual(VarType.Byte, dataItem.VarType, "Wrong vartype for IB200");
|
||||
Assert.AreEqual(200, dataItem.StartByteAdr, "Wrong startbyte for IB200");
|
||||
Assert.AreEqual(0, dataItem.BitAdr, "Wrong bit for IB200");
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void T07_ParseIW200()
|
||||
{
|
||||
DataItem dataItem = DataItem.FromAddress("IW200");
|
||||
|
||||
Assert.AreEqual(DataType.Input, dataItem.DataType, "Wrong datatype for IW200");
|
||||
Assert.AreEqual(0, dataItem.DB, "Wrong dbnumber for IW200");
|
||||
Assert.AreEqual(VarType.Word, dataItem.VarType, "Wrong vartype for IW200");
|
||||
Assert.AreEqual(200, dataItem.StartByteAdr, "Wrong startbyte for IW200");
|
||||
Assert.AreEqual(0, dataItem.BitAdr, "Wrong bit for IW200");
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void T08_ParseID200()
|
||||
{
|
||||
DataItem dataItem = DataItem.FromAddress("ID200");
|
||||
|
||||
Assert.AreEqual(DataType.Input, dataItem.DataType, "Wrong datatype for ID200");
|
||||
Assert.AreEqual(0, dataItem.DB, "Wrong dbnumber for ID200");
|
||||
Assert.AreEqual(VarType.DWord, dataItem.VarType, "Wrong vartype for ID200");
|
||||
Assert.AreEqual(200, dataItem.StartByteAdr, "Wrong startbyte for ID200");
|
||||
Assert.AreEqual(0, dataItem.BitAdr, "Wrong bit for ID200");
|
||||
}
|
||||
|
||||
|
||||
[TestMethod]
|
||||
public void T09_ParseQ2000_1()
|
||||
{
|
||||
DataItem dataItem = DataItem.FromAddress("Q2000.1");
|
||||
|
||||
Assert.AreEqual(DataType.Output, dataItem.DataType, "Wrong datatype for Q2000.1");
|
||||
Assert.AreEqual(0, dataItem.DB, "Wrong dbnumber for Q2000.1");
|
||||
Assert.AreEqual(VarType.Bit, dataItem.VarType, "Wrong vartype for Q2000.1");
|
||||
Assert.AreEqual(2000, dataItem.StartByteAdr, "Wrong startbyte for Q2000.1");
|
||||
Assert.AreEqual(1, dataItem.BitAdr, "Wrong bit for Q2000.1");
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void T10_ParseQB200()
|
||||
{
|
||||
DataItem dataItem = DataItem.FromAddress("QB200");
|
||||
|
||||
Assert.AreEqual(DataType.Output, dataItem.DataType, "Wrong datatype for QB200");
|
||||
Assert.AreEqual(0, dataItem.DB, "Wrong dbnumber for QB200");
|
||||
Assert.AreEqual(VarType.Byte, dataItem.VarType, "Wrong vartype for QB200");
|
||||
Assert.AreEqual(200, dataItem.StartByteAdr, "Wrong startbyte for QB200");
|
||||
Assert.AreEqual(0, dataItem.BitAdr, "Wrong bit for QB200");
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void T11_ParseQW200()
|
||||
{
|
||||
DataItem dataItem = DataItem.FromAddress("QW200");
|
||||
|
||||
Assert.AreEqual(DataType.Output, dataItem.DataType, "Wrong datatype for QW200");
|
||||
Assert.AreEqual(0, dataItem.DB, "Wrong dbnumber for QW200");
|
||||
Assert.AreEqual(VarType.Word, dataItem.VarType, "Wrong vartype for QW200");
|
||||
Assert.AreEqual(200, dataItem.StartByteAdr, "Wrong startbyte for QW200");
|
||||
Assert.AreEqual(0, dataItem.BitAdr, "Wrong bit for QW200");
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void T12_ParseQD200()
|
||||
{
|
||||
DataItem dataItem = DataItem.FromAddress("QD200");
|
||||
|
||||
Assert.AreEqual(DataType.Output, dataItem.DataType, "Wrong datatype for QD200");
|
||||
Assert.AreEqual(0, dataItem.DB, "Wrong dbnumber for QD200");
|
||||
Assert.AreEqual(VarType.DWord, dataItem.VarType, "Wrong vartype for QD200");
|
||||
Assert.AreEqual(200, dataItem.StartByteAdr, "Wrong startbyte for QD200");
|
||||
Assert.AreEqual(0, dataItem.BitAdr, "Wrong bit for QD200");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("S7.Net.UnitTest")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("S7Net.UnitTest")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2014")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("6f73e1b1-301b-471e-9f38-3dcbddbcfc21")]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
||||
BIN
S7.Net.UnitTest/Properties/S7.Net.snk
Normal file
BIN
S7.Net.UnitTest/Properties/S7.Net.snk
Normal file
Binary file not shown.
97
S7.Net.UnitTest/ProtocolTests.cs
Normal file
97
S7.Net.UnitTest/ProtocolTests.cs
Normal file
@@ -0,0 +1,97 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using S7.Net;
|
||||
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
using S7.Net.Protocol;
|
||||
using System.Collections;
|
||||
|
||||
namespace S7.Net.UnitTest
|
||||
{
|
||||
[TestClass]
|
||||
public class ProtocolUnitTest
|
||||
{
|
||||
public TestContext TestContext { get; set; }
|
||||
|
||||
[TestMethod]
|
||||
public async Task TPKT_Read()
|
||||
{
|
||||
var m = new MemoryStream(StringToByteArray("0300002902f0803203000000010002001400000401ff0400807710000100000103000000033f8ccccd"));
|
||||
var t = TPKT.Read(m);
|
||||
Assert.AreEqual(0x03, t.Version);
|
||||
Assert.AreEqual(0x29, t.Length);
|
||||
m.Position = 0;
|
||||
t = await TPKT.ReadAsync(m, TestContext.CancellationTokenSource.Token);
|
||||
Assert.AreEqual(0x03, t.Version);
|
||||
Assert.AreEqual(0x29, t.Length);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
[ExpectedException(typeof(TPKTInvalidException))]
|
||||
public void TPKT_ReadShort()
|
||||
{
|
||||
var m = new MemoryStream(StringToByteArray("0300002902f0803203000000010002001400000401ff040080"));
|
||||
var t = TPKT.Read(m);
|
||||
}
|
||||
|
||||
|
||||
[TestMethod]
|
||||
[ExpectedException(typeof(TPKTInvalidException))]
|
||||
public async Task TPKT_ReadShortAsync()
|
||||
{
|
||||
var m = new MemoryStream(StringToByteArray("0300002902f0803203000000010002001400000401ff040080"));
|
||||
var t = await TPKT.ReadAsync(m, TestContext.CancellationTokenSource.Token);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void COTP_ReadTSDU()
|
||||
{
|
||||
var expected = StringToByteArray("320700000400000800080001120411440100ff09000400000000");
|
||||
var m = new MemoryStream(StringToByteArray("0300000702f0000300000702f0000300002102f080320700000400000800080001120411440100ff09000400000000"));
|
||||
var t = COTP.TSDU.Read(m);
|
||||
Assert.IsTrue(expected.SequenceEqual(t));
|
||||
m.Position = 0;
|
||||
t = COTP.TSDU.ReadAsync(m, TestContext.CancellationTokenSource.Token).Result;
|
||||
Assert.IsTrue(expected.SequenceEqual(t));
|
||||
}
|
||||
|
||||
public static byte[] StringToByteArray(string hex)
|
||||
{
|
||||
return Enumerable.Range(0, hex.Length)
|
||||
.Where(x => x % 2 == 0)
|
||||
.Select(x => Convert.ToByte(hex.Substring(x, 2), 16))
|
||||
.ToArray();
|
||||
}
|
||||
|
||||
|
||||
[TestMethod]
|
||||
public void TestResponseCode()
|
||||
{
|
||||
var expected = StringToByteArray("320700000400000800080001120411440100ff09000400000000");
|
||||
var m = new MemoryStream(StringToByteArray("0300000702f0000300000702f0000300002102f080320700000400000800080001120411440100ff09000400000000"));
|
||||
var t = COTP.TSDU.Read(m);
|
||||
Assert.IsTrue(expected.SequenceEqual(t));
|
||||
|
||||
|
||||
// Test all possible byte values. Everything except 0xff should throw an exception.
|
||||
var testData = Enumerable.Range(0, 256).Select(i => new { StatusCode = (ReadWriteErrorCode)i, ThrowsException = i != (byte)ReadWriteErrorCode.Success });
|
||||
|
||||
foreach (var entry in testData)
|
||||
{
|
||||
if (entry.ThrowsException)
|
||||
{
|
||||
Assert.ThrowsException<Exception>(() => Plc.ValidateResponseCode(entry.StatusCode));
|
||||
}
|
||||
else
|
||||
{
|
||||
Plc.ValidateResponseCode(entry.StatusCode);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,108 +1,33 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{303CCED6-9ABC-4899-A509-743341AAA804}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>S7.UnitTest</RootNamespace>
|
||||
<AssemblyName>S7Net.UnitTest</AssemblyName>
|
||||
<TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<ProjectTypeGuids>{3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
|
||||
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">10.0</VisualStudioVersion>
|
||||
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
|
||||
<ReferencePath>$(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages</ReferencePath>
|
||||
<IsCodedUITest>False</IsCodedUITest>
|
||||
<TestProjectType>UnitTest</TestProjectType>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<TargetFrameworks>net452;netcoreapp3.1</TargetFrameworks>
|
||||
|
||||
<SignAssembly>true</SignAssembly>
|
||||
<AssemblyOriginatorKeyFile>Properties\S7.Net.snk</AssemblyOriginatorKeyFile>
|
||||
<IsPackable>false</IsPackable>
|
||||
<Copyright>Copyright © 2014</Copyright>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.ServiceProcess" />
|
||||
<Reference Include="System.Windows.Forms" />
|
||||
<PackageReference Include="GitHubActionsTestLogger" Version="1.1.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.7.0" />
|
||||
<PackageReference Include="MSTest.TestAdapter" Version="2.1.2" />
|
||||
<PackageReference Include="MSTest.TestFramework" Version="2.1.2" />
|
||||
<PackageReference Include="coverlet.collector" Version="1.3.0">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
<Choose>
|
||||
<When Condition="('$(VisualStudioVersion)' == '10.0' or '$(VisualStudioVersion)' == '') and '$(TargetFrameworkVersion)' == 'v3.5'">
|
||||
<ItemGroup>
|
||||
<Reference Include="Microsoft.VisualStudio.QualityTools.UnitTestFramework, Version=10.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL" />
|
||||
</ItemGroup>
|
||||
</When>
|
||||
<Otherwise>
|
||||
<ItemGroup>
|
||||
<Reference Include="Microsoft.VisualStudio.QualityTools.UnitTestFramework" />
|
||||
</ItemGroup>
|
||||
</Otherwise>
|
||||
</Choose>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Include="ConvertersUnitTest.cs" />
|
||||
<Compile Include="Helpers\ConsoleManager.cs" />
|
||||
<Compile Include="Helpers\NativeMethods.cs" />
|
||||
<Compile Include="Helpers\S7TestServer.cs" />
|
||||
<Compile Include="Helpers\TestClassWithArrays.cs" />
|
||||
<Compile Include="Helpers\TestClassWithCustomType.cs" />
|
||||
<Compile Include="Helpers\TestClassWithPrivateSetters.cs" />
|
||||
<Compile Include="Helpers\TestLongClass.cs" />
|
||||
<Compile Include="Snap7\snap7.net.cs" />
|
||||
<Compile Include="Helpers\TestClass.cs" />
|
||||
<Compile Include="Helpers\TestStruct.cs" />
|
||||
<Compile Include="S7NetTests.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="Helpers\TestLongStruct.cs" />
|
||||
<ProjectReference Include="..\S7.Net\S7.Net.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Content Include="snap7.dll">
|
||||
<None Update="runtimes\win-x64\native\snap7.dll" Link="snap7.dll">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\S7.Net\S7.Net.csproj">
|
||||
<Project>{bfd484f9-3f04-42a2-bf2a-60a189a25dcf}</Project>
|
||||
<Name>S7.Net</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<Choose>
|
||||
<When Condition="'$(VisualStudioVersion)' == '10.0' And '$(IsCodedUITest)' == 'True'">
|
||||
<ItemGroup>
|
||||
<Reference Include="Microsoft.VisualStudio.QualityTools.CodedUITestFramework, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.VisualStudio.TestTools.UITest.Common, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.VisualStudio.TestTools.UITest.Extension, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.VisualStudio.TestTools.UITesting, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
</When>
|
||||
</Choose>
|
||||
<Import Project="$(VSToolsPath)\TeamTest\Microsoft.TestTools.targets" Condition="Exists('$(VSToolsPath)\TeamTest\Microsoft.TestTools.targets')" />
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
<Target Name="BeforeBuild">
|
||||
</Target>
|
||||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
</Project>
|
||||
</Project>
|
||||
|
||||
954
S7.Net.UnitTest/S7NetTestsAsync.cs
Normal file
954
S7.Net.UnitTest/S7NetTestsAsync.cs
Normal file
@@ -0,0 +1,954 @@
|
||||
#region Using
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using S7.Net.UnitTest.Helpers;
|
||||
using S7.Net.Types;
|
||||
using S7.UnitTest.Helpers;
|
||||
using System.Threading.Tasks;
|
||||
using System.Threading;
|
||||
|
||||
#endregion
|
||||
|
||||
/**
|
||||
* About the tests:
|
||||
* ---------------------------------------------------------------------------
|
||||
* The tests were written to show how to use this library to read and write
|
||||
* different types of values, how to box and unbox values and of course to
|
||||
* address some of the bugs of the library.
|
||||
* These tests are not meant to cover 100% the code, but to check that once a
|
||||
* variable is written, it stores the correct value.
|
||||
* ----------------------------------------------------------------------------
|
||||
* The plc used for the tests is the S7 "server" provided by Snap7 opensource
|
||||
* library, that you can get for free here:http://snap7.sourceforge.net/
|
||||
* The implementation of the server will not be discussed here, but there are
|
||||
* some issues with the interop that cause the server, and unit test, to fail
|
||||
* under some circumstances, like "click on Run all tests" too much.
|
||||
* This doesn't mean that S7.Net has bugs, but that the implementation of the
|
||||
* server has problems.
|
||||
*
|
||||
*/
|
||||
|
||||
//Tests for Async Methods
|
||||
|
||||
namespace S7.Net.UnitTest
|
||||
{
|
||||
public partial class S7NetTests
|
||||
{
|
||||
#region Tests
|
||||
[TestMethod]
|
||||
public async Task Test_Async_Connection()
|
||||
{
|
||||
if (plc.IsConnected == false)
|
||||
{
|
||||
await plc.OpenAsync();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read/Write a single Int16 or UInt16 with a single request.
|
||||
/// Test that writing a UInt16 (ushort) and reading it gives the correct value.
|
||||
/// Test also that writing a Int16 (short) and reading it gives the correct value.
|
||||
/// </summary>
|
||||
[TestMethod]
|
||||
public async Task Test_Async_WriteAndReadInt16Variable()
|
||||
{
|
||||
Assert.IsTrue(plc.IsConnected, "Before executing this test, the plc must be connected. Check constructor.");
|
||||
|
||||
// To write a ushort i don't need any cast, only unboxing must be done
|
||||
ushort val = 40000;
|
||||
await plc.WriteAsync("DB1.DBW0", val);
|
||||
ushort result = (ushort)await plc.ReadAsync("DB1.DBW0");
|
||||
Assert.AreEqual(val, result, "A ushort goes from 0 to 64512");
|
||||
|
||||
// To write a short i need to convert it to UShort, then i need to reconvert the readed value to get
|
||||
// the negative sign back
|
||||
// Depending if i'm writing on a DWORD or on a DEC, i will see ushort or short value in the plc
|
||||
short value = -100;
|
||||
Assert.IsTrue(plc.IsConnected, "After connecting, IsConnected must be set to true");
|
||||
await plc.WriteAsync("DB1.DBW0", value.ConvertToUshort());
|
||||
short result2 = ((ushort)await plc.ReadAsync("DB1.DBW0")).ConvertToShort();
|
||||
Assert.AreEqual(value, result2, "A short goes from -32767 to 32766");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read/Write a single Int32 or UInt32 with a single request.
|
||||
/// Test that writing a UInt32 (uint) and reading it gives the correct value.
|
||||
/// Test also that writing a Int32 (int) and reading it gives the correct value.
|
||||
/// </summary>
|
||||
[TestMethod]
|
||||
public async Task Test_Async_WriteAndReadInt32Variable()
|
||||
{
|
||||
Assert.IsTrue(plc.IsConnected, "Before executing this test, the plc must be connected. Check constructor.");
|
||||
|
||||
// To write a uint I don't need any cast, only unboxing must be done
|
||||
int val = 1000;
|
||||
await plc.WriteAsync("DB1.DBD40", val);
|
||||
int result = ((uint)await plc.ReadAsync("DB1.DBD40")).ConvertToInt();
|
||||
Assert.AreEqual(val, result);
|
||||
|
||||
// To write a int I need to convert it to uint, then I need to reconvert the readed value to get
|
||||
// the negative sign back
|
||||
// Depending if I'm writing on a DBD or on a LONG, I will see uint or int value in the plc
|
||||
int value = -60000;
|
||||
await plc.WriteAsync("DB1.DBD60", value);
|
||||
int result2 = ((uint)await plc.ReadAsync("DB1.DBD60")).ConvertToInt();
|
||||
Assert.AreEqual(value, result2);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read/Write a single REAL with a single request.
|
||||
/// Test that writing a float and reading it gives the correct value.
|
||||
/// </summary>
|
||||
[TestMethod]
|
||||
public async Task Test_Async_WriteAndReadRealVariables()
|
||||
{
|
||||
Assert.IsTrue(plc.IsConnected, "Before executing this test, the plc must be connected. Check constructor.");
|
||||
|
||||
// Reading and writing a float is quite complicated, because it needs to be converted to DWord before the write,
|
||||
// then reconvert to float after the read. Float values can contain only 7 digits, so no precision is lost.
|
||||
float val2 = 1234567;
|
||||
await plc.WriteAsync("DB1.DBD40", val2.ConvertToUInt());
|
||||
float result2 = ((uint)await plc.ReadAsync("DB1.DBD40")).ConvertToFloat();
|
||||
Assert.AreEqual(val2, result2);
|
||||
|
||||
float val3 = 12.34567f;
|
||||
await plc.WriteAsync("DB1.DBD40", val3.ConvertToUInt());
|
||||
float result3 = ((uint)await plc.ReadAsync("DB1.DBD40")).ConvertToFloat();
|
||||
Assert.AreEqual(val3, result3);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write/Read a large amount of data to test PDU max
|
||||
/// </summary>
|
||||
[TestMethod]
|
||||
public async Task Test_Async_WriteLargeByteArray()
|
||||
{
|
||||
Assert.IsTrue(plc.IsConnected, "Before executing this test, the plc must be connected. Check constructor.");
|
||||
|
||||
var randomEngine = new Random();
|
||||
var data = new byte[8192];
|
||||
var db = 2;
|
||||
randomEngine.NextBytes(data);
|
||||
|
||||
await plc.WriteBytesAsync(DataType.DataBlock, db, 0, data);
|
||||
|
||||
var readData = await plc.ReadBytesAsync(DataType.DataBlock, db, 0, data.Length);
|
||||
|
||||
CollectionAssert.AreEqual(data, readData);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read/Write a class that has the same properties of a DB with the same field in the same order
|
||||
/// </summary>
|
||||
[TestMethod]
|
||||
public async Task Test_Async_ReadAndWriteClass()
|
||||
{
|
||||
Assert.IsTrue(plc.IsConnected, "Before executing this test, the plc must be connected. Check constructor.");
|
||||
|
||||
TestClass tc = new TestClass
|
||||
{
|
||||
BitVariable00 = true,
|
||||
BitVariable10 = true,
|
||||
DIntVariable = -100000,
|
||||
IntVariable = -15000,
|
||||
LRealVariable = -154.789,
|
||||
RealVariable = -154.789f,
|
||||
DWordVariable = 850
|
||||
};
|
||||
|
||||
await plc.WriteClassAsync(tc, DB2);
|
||||
TestClass tc2 = new TestClass();
|
||||
// Values that are read from a class are stored inside the class itself, that is passed by reference
|
||||
await plc.ReadClassAsync(tc2, DB2);
|
||||
Assert.AreEqual(tc.BitVariable00, tc2.BitVariable00);
|
||||
Assert.AreEqual(tc.BitVariable10, tc2.BitVariable10);
|
||||
Assert.AreEqual(tc.DIntVariable, tc2.DIntVariable);
|
||||
Assert.AreEqual(tc.IntVariable, tc2.IntVariable);
|
||||
Assert.AreEqual(tc.LRealVariable, tc2.LRealVariable);
|
||||
Assert.AreEqual(tc.RealVariable, tc2.RealVariable);
|
||||
Assert.AreEqual(tc.DWordVariable, tc2.DWordVariable);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task Test_Async_ReadAndWriteNestedClass()
|
||||
{
|
||||
Assert.IsTrue(plc.IsConnected, "Before executing this test, the plc must be connected. Check constructor.");
|
||||
|
||||
TestClassWithNestedClass tc = new TestClassWithNestedClass
|
||||
{
|
||||
BitVariable00 = true,
|
||||
BitVariable01 = new TestClassInnerWithBool { BitVariable00 = true },
|
||||
ByteVariable02 = new TestClassInnerWithByte { ByteVariable00 = 128 },
|
||||
BitVariable03 = true,
|
||||
ShortVariable04 = new TestClassInnerWithShort { ShortVarialbe00 = -15000 }
|
||||
};
|
||||
|
||||
await plc.WriteClassAsync(tc, DB4);
|
||||
TestClassWithNestedClass tc2 = new TestClassWithNestedClass();
|
||||
// Values that are read from a class are stored inside the class itself, that is passed by reference
|
||||
await plc.ReadClassAsync(tc2, DB4);
|
||||
Assert.AreEqual(tc.BitVariable00, tc2.BitVariable00);
|
||||
Assert.AreEqual(tc.BitVariable01.BitVariable00, tc2.BitVariable01.BitVariable00);
|
||||
Assert.AreEqual(tc.ByteVariable02.ByteVariable00, tc2.ByteVariable02.ByteVariable00);
|
||||
Assert.AreEqual(tc.BitVariable03, tc2.BitVariable03);
|
||||
Assert.AreEqual(tc.ShortVariable04.ShortVarialbe00, tc2.ShortVariable04.ShortVarialbe00);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read/Write a struct that has the same properties of a DB with the same field in the same order
|
||||
/// </summary>
|
||||
[TestMethod]
|
||||
public async Task Test_Async_ReadAndWriteStruct()
|
||||
{
|
||||
Assert.IsTrue(plc.IsConnected, "Before executing this test, the plc must be connected. Check constructor.");
|
||||
|
||||
TestStruct tc = new TestStruct
|
||||
{
|
||||
BitVariable00 = true,
|
||||
BitVariable10 = true,
|
||||
DIntVariable = -100000,
|
||||
IntVariable = -15000,
|
||||
LRealVariable = -154.789,
|
||||
RealVariable = -154.789f,
|
||||
DWordVariable = 850,
|
||||
WStringVariable = "ÄÜÉÊéà",
|
||||
StringVariable = "Hallo"
|
||||
};
|
||||
plc.WriteStruct(tc, DB2);
|
||||
// Values that are read from a struct are stored in a new struct, returned by the funcion ReadStruct
|
||||
TestStruct tc2 = (TestStruct)await plc.ReadStructAsync(typeof(TestStruct), DB2);
|
||||
Assert.AreEqual(tc.BitVariable00, tc2.BitVariable00);
|
||||
Assert.AreEqual(tc.BitVariable10, tc2.BitVariable10);
|
||||
Assert.AreEqual(tc.DIntVariable, tc2.DIntVariable);
|
||||
Assert.AreEqual(tc.IntVariable, tc2.IntVariable);
|
||||
Assert.AreEqual(tc.LRealVariable, tc2.LRealVariable);
|
||||
Assert.AreEqual(tc.RealVariable, tc2.RealVariable);
|
||||
Assert.AreEqual(tc.DWordVariable, tc2.DWordVariable);
|
||||
Assert.AreEqual(tc.WStringVariable, tc2.WStringVariable);
|
||||
Assert.AreEqual(tc.StringVariable, tc2.StringVariable);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read/Write a struct that has the same properties of a DB with the same field in the same order
|
||||
/// </summary>
|
||||
[TestMethod]
|
||||
public async Task Test_Async_ReadAndWriteLongStruct()
|
||||
{
|
||||
Assert.IsTrue(plc.IsConnected, "Before executing this test, the plc must be connected. Check constructor.");
|
||||
|
||||
TestLongStruct tc = new TestLongStruct
|
||||
{
|
||||
IntVariable0 = 0,
|
||||
IntVariable1 = 1,
|
||||
IntVariable10 = 10,
|
||||
IntVariable11 = 11,
|
||||
IntVariable20 = 20,
|
||||
IntVariable21 = 21,
|
||||
IntVariable30 = 30,
|
||||
IntVariable31 = 31,
|
||||
IntVariable40 = 40,
|
||||
IntVariable41 = 41,
|
||||
IntVariable50 = 50,
|
||||
IntVariable51 = 51,
|
||||
IntVariable60 = 60,
|
||||
IntVariable61 = 61,
|
||||
IntVariable70 = 70,
|
||||
IntVariable71 = 71,
|
||||
IntVariable80 = 80,
|
||||
IntVariable81 = 81,
|
||||
IntVariable90 = 90,
|
||||
IntVariable91 = 91,
|
||||
IntVariable100 = 100,
|
||||
IntVariable101 = 101,
|
||||
IntVariable110 = 200,
|
||||
IntVariable111 = 201
|
||||
};
|
||||
plc.WriteStruct(tc, DB2);
|
||||
// Values that are read from a struct are stored in a new struct, returned by the funcion ReadStruct
|
||||
TestLongStruct tc2 = (TestLongStruct)await plc.ReadStructAsync(typeof(TestLongStruct), DB2);
|
||||
Assert.AreEqual(tc.IntVariable0, tc2.IntVariable0);
|
||||
Assert.AreEqual(tc.IntVariable1, tc2.IntVariable1);
|
||||
Assert.AreEqual(tc.IntVariable10, tc2.IntVariable10);
|
||||
Assert.AreEqual(tc.IntVariable11, tc2.IntVariable11);
|
||||
Assert.AreEqual(tc.IntVariable20, tc2.IntVariable20);
|
||||
Assert.AreEqual(tc.IntVariable21, tc2.IntVariable21);
|
||||
Assert.AreEqual(tc.IntVariable30, tc2.IntVariable30);
|
||||
Assert.AreEqual(tc.IntVariable31, tc2.IntVariable31);
|
||||
Assert.AreEqual(tc.IntVariable40, tc2.IntVariable40);
|
||||
Assert.AreEqual(tc.IntVariable41, tc2.IntVariable41);
|
||||
Assert.AreEqual(tc.IntVariable50, tc2.IntVariable50);
|
||||
Assert.AreEqual(tc.IntVariable51, tc2.IntVariable51);
|
||||
Assert.AreEqual(tc.IntVariable60, tc2.IntVariable60);
|
||||
Assert.AreEqual(tc.IntVariable61, tc2.IntVariable61);
|
||||
Assert.AreEqual(tc.IntVariable70, tc2.IntVariable70);
|
||||
Assert.AreEqual(tc.IntVariable71, tc2.IntVariable71);
|
||||
Assert.AreEqual(tc.IntVariable80, tc2.IntVariable80);
|
||||
Assert.AreEqual(tc.IntVariable81, tc2.IntVariable81);
|
||||
Assert.AreEqual(tc.IntVariable90, tc2.IntVariable90);
|
||||
Assert.AreEqual(tc.IntVariable91, tc2.IntVariable91);
|
||||
Assert.AreEqual(tc.IntVariable100, tc2.IntVariable100);
|
||||
Assert.AreEqual(tc.IntVariable101, tc2.IntVariable101);
|
||||
Assert.AreEqual(tc.IntVariable110, tc2.IntVariable110);
|
||||
Assert.AreEqual(tc.IntVariable111, tc2.IntVariable111);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read/Write a class that has the same properties of a DB with the same field in the same order
|
||||
/// </summary>
|
||||
[TestMethod]
|
||||
public async Task Test_Async_ReadAndWriteLongClass()
|
||||
{
|
||||
Assert.IsTrue(plc.IsConnected, "Before executing this test, the plc must be connected. Check constructor.");
|
||||
|
||||
TestLongClass tc = new TestLongClass
|
||||
{
|
||||
IntVariable0 = 0,
|
||||
IntVariable1 = 1,
|
||||
IntVariable10 = 10,
|
||||
IntVariable11 = 11,
|
||||
IntVariable20 = 20,
|
||||
IntVariable21 = 21,
|
||||
IntVariable30 = 30,
|
||||
IntVariable31 = 31,
|
||||
IntVariable40 = 40,
|
||||
IntVariable41 = 41,
|
||||
IntVariable50 = 50,
|
||||
IntVariable51 = 51,
|
||||
IntVariable60 = 60,
|
||||
IntVariable61 = 61,
|
||||
IntVariable70 = 70,
|
||||
IntVariable71 = 71,
|
||||
IntVariable80 = 80,
|
||||
IntVariable81 = 81,
|
||||
IntVariable90 = 90,
|
||||
IntVariable91 = 91,
|
||||
IntVariable100 = 100,
|
||||
IntVariable101 = 101,
|
||||
IntVariable110 = 200,
|
||||
IntVariable111 = 201
|
||||
};
|
||||
await plc.WriteClassAsync(tc, DB2);
|
||||
// Values that are read from a struct are stored in a new struct, returned by the funcion ReadStruct
|
||||
TestLongClass tc2 = new TestLongClass();
|
||||
await plc.ReadClassAsync(tc2, DB2);
|
||||
Assert.AreEqual(tc.IntVariable0, tc2.IntVariable0);
|
||||
Assert.AreEqual(tc.IntVariable1, tc2.IntVariable1);
|
||||
Assert.AreEqual(tc.IntVariable10, tc2.IntVariable10);
|
||||
Assert.AreEqual(tc.IntVariable11, tc2.IntVariable11);
|
||||
Assert.AreEqual(tc.IntVariable20, tc2.IntVariable20);
|
||||
Assert.AreEqual(tc.IntVariable21, tc2.IntVariable21);
|
||||
Assert.AreEqual(tc.IntVariable30, tc2.IntVariable30);
|
||||
Assert.AreEqual(tc.IntVariable31, tc2.IntVariable31);
|
||||
Assert.AreEqual(tc.IntVariable40, tc2.IntVariable40);
|
||||
Assert.AreEqual(tc.IntVariable41, tc2.IntVariable41);
|
||||
Assert.AreEqual(tc.IntVariable50, tc2.IntVariable50);
|
||||
Assert.AreEqual(tc.IntVariable51, tc2.IntVariable51);
|
||||
Assert.AreEqual(tc.IntVariable60, tc2.IntVariable60);
|
||||
Assert.AreEqual(tc.IntVariable61, tc2.IntVariable61);
|
||||
Assert.AreEqual(tc.IntVariable70, tc2.IntVariable70);
|
||||
Assert.AreEqual(tc.IntVariable71, tc2.IntVariable71);
|
||||
Assert.AreEqual(tc.IntVariable80, tc2.IntVariable80);
|
||||
Assert.AreEqual(tc.IntVariable81, tc2.IntVariable81);
|
||||
Assert.AreEqual(tc.IntVariable90, tc2.IntVariable90);
|
||||
Assert.AreEqual(tc.IntVariable91, tc2.IntVariable91);
|
||||
Assert.AreEqual(tc.IntVariable100, tc2.IntVariable100);
|
||||
Assert.AreEqual(tc.IntVariable101, tc2.IntVariable101);
|
||||
Assert.AreEqual(tc.IntVariable110, tc2.IntVariable110);
|
||||
Assert.AreEqual(tc.IntVariable111, tc2.IntVariable111);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tests that a read and a write on addresses bigger than 8192 are executed correctly
|
||||
/// </summary>
|
||||
[TestMethod]
|
||||
public async Task Test_Async_WriteAndReadInt16VariableAddress8192()
|
||||
{
|
||||
Assert.IsTrue(plc.IsConnected, "Before executing this test, the plc must be connected. Check constructor.");
|
||||
|
||||
// To write a ushort i don't need any cast, only unboxing must be done
|
||||
ushort val = 8192;
|
||||
await plc.WriteAsync("DB2.DBW8192", val);
|
||||
ushort result = (ushort)await plc.ReadAsync("DB2.DBW8192");
|
||||
Assert.AreEqual(val, result, "A ushort goes from 0 to 64512");
|
||||
|
||||
// To write a short i need to convert it to UShort, then i need to reconvert the readed value to get
|
||||
// the negative sign back
|
||||
// Depending if i'm writing on a DWORD or on a DEC, i will see ushort or short value in the plc
|
||||
short value = -8192;
|
||||
Assert.IsTrue(plc.IsConnected, "After connecting, IsConnected must be set to true");
|
||||
await plc.WriteAsync("DB2.DBW8192", value.ConvertToUshort());
|
||||
short result2 = ((ushort)await plc.ReadAsync("DB2.DBW8192")).ConvertToShort();
|
||||
Assert.AreEqual(value, result2, "A short goes from -32767 to 32766");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tests that a read and a write on addresses bigger than 8192 are executed correctly
|
||||
/// </summary>
|
||||
[TestMethod]
|
||||
public async Task Test_Async_WriteAndReadInt16VariableAddress16384()
|
||||
{
|
||||
Assert.IsTrue(plc.IsConnected, "Before executing this test, the plc must be connected. Check constructor.");
|
||||
|
||||
// To write a ushort i don't need any cast, only unboxing must be done
|
||||
ushort val = 16384;
|
||||
await plc.WriteAsync("DB2.DBW16384", val);
|
||||
ushort result = (ushort)await plc.ReadAsync("DB2.DBW16384");
|
||||
Assert.AreEqual(val, result, "A ushort goes from 0 to 64512");
|
||||
|
||||
// To write a short i need to convert it to UShort, then i need to reconvert the readed value to get
|
||||
// the negative sign back
|
||||
// Depending if i'm writing on a DWORD or on a DEC, i will see ushort or short value in the plc
|
||||
short value = -16384;
|
||||
Assert.IsTrue(plc.IsConnected, "After connecting, IsConnected must be set to true");
|
||||
await plc.WriteAsync("DB2.DBW16384", value.ConvertToUshort());
|
||||
short result2 = ((ushort)await plc.ReadAsync("DB2.DBW16384")).ConvertToShort();
|
||||
Assert.AreEqual(value, result2, "A short goes from -32767 to 32766");
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task Test_Async_ReadMultipleBytes()
|
||||
{
|
||||
Assert.IsTrue(plc.IsConnected, "Before executing this test, the plc must be connected. Check constructor.");
|
||||
bool val = true;
|
||||
await plc.WriteAsync("DB2.DBX0.5", val);
|
||||
bool result = (bool)await plc.ReadAsync("DB2.DBX0.5");
|
||||
Assert.AreEqual(val, result);
|
||||
|
||||
ushort val1 = 16384;
|
||||
await plc.WriteAsync("DB2.DBW16384", val1);
|
||||
ushort result1 = (ushort)await plc.ReadAsync("DB2.DBW16384");
|
||||
Assert.AreEqual(val1, result1, "A ushort goes from 0 to 64512");
|
||||
|
||||
bool val2 = true;
|
||||
await plc.WriteAsync("DB2.DBX8192.7", val2);
|
||||
bool result2 = (bool)await plc.ReadAsync("DB2.DBX8192.7");
|
||||
Assert.AreEqual(val2, result2);
|
||||
|
||||
ushort val3 = 129;
|
||||
await plc.WriteAsync("DB2.DBW16", val3);
|
||||
ushort result3 = (ushort)await plc.ReadAsync("DB2.DBW16");
|
||||
Assert.AreEqual(val3, result3, "A ushort goes from 0 to 64512");
|
||||
|
||||
byte[] val4 = new byte[] { 0x12, 0x34 };
|
||||
await plc.WriteAsync("DB2.DBB2048", val4[0]);
|
||||
await plc.WriteAsync("DB2.DBB2049", val4[1]);
|
||||
byte result4b0 = (byte)await plc.ReadAsync("DB2.DBB2048");
|
||||
byte result4b1 = (byte)await plc.ReadAsync("DB2.DBB2049");
|
||||
Assert.AreEqual(val4[0], result4b0);
|
||||
Assert.AreEqual(val4[1], result4b1);
|
||||
|
||||
bool val6 = true;
|
||||
await plc.WriteAsync("DB2.DBX16384.6", val6);
|
||||
bool result6 = (bool)await plc.ReadAsync("DB2.DBX16384.6");
|
||||
Assert.AreEqual(val6, result6);
|
||||
|
||||
var dataItems = new List<DataItem>()
|
||||
{
|
||||
new DataItem
|
||||
{
|
||||
Count = 1,
|
||||
DataType = DataType.DataBlock,
|
||||
DB = 2,
|
||||
StartByteAdr = 0,
|
||||
BitAdr = 5,
|
||||
VarType = VarType.Bit
|
||||
}
|
||||
,new DataItem
|
||||
{
|
||||
Count = 1,
|
||||
DataType = DataType.DataBlock,
|
||||
DB = 2,
|
||||
StartByteAdr = 16384,
|
||||
VarType = VarType.Word
|
||||
},
|
||||
new DataItem
|
||||
{
|
||||
Count = 1,
|
||||
DataType = DataType.DataBlock,
|
||||
DB = 2,
|
||||
StartByteAdr = 8192,
|
||||
BitAdr = 7,
|
||||
VarType = VarType.Bit
|
||||
},
|
||||
new DataItem
|
||||
{
|
||||
Count = 1,
|
||||
DataType = DataType.DataBlock,
|
||||
DB = 2,
|
||||
StartByteAdr = 16,
|
||||
VarType = VarType.Word
|
||||
},
|
||||
// single byte
|
||||
new DataItem
|
||||
{
|
||||
Count = 1,
|
||||
DataType = DataType.DataBlock,
|
||||
DB = 2,
|
||||
StartByteAdr = 2048,
|
||||
VarType = VarType.Byte
|
||||
},
|
||||
// multiple bytes
|
||||
new DataItem
|
||||
{
|
||||
Count = 2,
|
||||
DataType = DataType.DataBlock,
|
||||
DB = 2,
|
||||
StartByteAdr = 2048,
|
||||
VarType = VarType.Byte
|
||||
},
|
||||
new DataItem
|
||||
{
|
||||
Count = 1,
|
||||
DataType = DataType.DataBlock,
|
||||
DB = 2,
|
||||
StartByteAdr = 16384,
|
||||
BitAdr = 6,
|
||||
VarType = VarType.Bit
|
||||
},
|
||||
};
|
||||
|
||||
var dataItemsRes = await plc.ReadMultipleVarsAsync(dataItems);
|
||||
|
||||
Assert.AreEqual(val, dataItemsRes[0].Value);
|
||||
Assert.AreEqual(val1, dataItemsRes[1].Value);
|
||||
Assert.AreEqual(val2, dataItemsRes[2].Value);
|
||||
Assert.AreEqual(val3, dataItemsRes[3].Value);
|
||||
Assert.AreEqual(val4[0], dataItemsRes[4].Value);
|
||||
Assert.AreEqual(val4[0], ((byte[])dataItemsRes[5].Value)[0]); //dataItem[5].Value should be byte[2]
|
||||
Assert.AreEqual(val4[1], ((byte[])dataItemsRes[5].Value)[1]);
|
||||
Assert.AreEqual(val6, dataItemsRes[6].Value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tests that a read and a write on addresses bigger than 8192 are executed correctly
|
||||
/// </summary>
|
||||
[TestMethod]
|
||||
public async Task Test_Async_WriteAndReadBooleanVariable()
|
||||
{
|
||||
Assert.IsTrue(plc.IsConnected, "Before executing this test, the plc must be connected. Check constructor.");
|
||||
|
||||
// tests when writing true/false
|
||||
await plc.WriteAsync("DB1.DBX0.0", false);
|
||||
var boolVariable = (bool)await plc.ReadAsync("DB1.DBX0.0");
|
||||
Assert.IsFalse(boolVariable);
|
||||
|
||||
await plc.WriteAsync("DB1.DBX0.0", true);
|
||||
boolVariable = (bool)await plc.ReadAsync("DB1.DBX0.0");
|
||||
Assert.IsTrue(boolVariable);
|
||||
|
||||
// tests when writing 0/1
|
||||
await plc.WriteAsync("DB1.DBX0.0", 0);
|
||||
boolVariable = (bool)await plc.ReadAsync("DB1.DBX0.0");
|
||||
Assert.IsFalse(boolVariable);
|
||||
|
||||
await plc.WriteAsync("DB1.DBX0.0", 1);
|
||||
boolVariable = (bool)await plc.ReadAsync("DB1.DBX0.0");
|
||||
Assert.IsTrue(boolVariable);
|
||||
|
||||
await plc.WriteAsync("DB1.DBX0.7", 1);
|
||||
boolVariable = (bool)await plc.ReadAsync("DB1.DBX0.7");
|
||||
Assert.IsTrue(boolVariable);
|
||||
|
||||
await plc.WriteAsync("DB1.DBX0.7", 0);
|
||||
boolVariable = (bool)await plc.ReadAsync("DB1.DBX0.7");
|
||||
Assert.IsFalse(boolVariable);
|
||||
|
||||
await plc.WriteAsync("DB1.DBX658.0", 1);
|
||||
boolVariable = (bool)await plc.ReadAsync("DB1.DBX658.0");
|
||||
Assert.IsTrue(boolVariable);
|
||||
|
||||
await plc.WriteAsync("DB1.DBX658.7", 1);
|
||||
boolVariable = (bool)await plc.ReadAsync("DB1.DBX658.7");
|
||||
Assert.IsTrue(boolVariable);
|
||||
|
||||
await plc.WriteAsync("DB2.DBX9658.0", 1);
|
||||
boolVariable = (bool)await plc.ReadAsync("DB2.DBX9658.0");
|
||||
Assert.IsTrue(boolVariable);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task Test_Async_ReadClassIgnoresNonPublicSetters()
|
||||
{
|
||||
Assert.IsTrue(plc.IsConnected, "Before executing this test, the plc must be connected. Check constructor.");
|
||||
|
||||
TestClassWithPrivateSetters tc = new TestClassWithPrivateSetters
|
||||
{
|
||||
BitVariable00 = true,
|
||||
BitVariable10 = true,
|
||||
DIntVariable = -100000,
|
||||
IntVariable = -15000,
|
||||
LRealVariable = -154.789,
|
||||
RealVariable = -154.789f,
|
||||
DWordVariable = 850
|
||||
};
|
||||
|
||||
await plc.WriteClassAsync(tc, DB2);
|
||||
|
||||
TestClassWithPrivateSetters tc2 = new TestClassWithPrivateSetters();
|
||||
// Values that are read from a class are stored inside the class itself, that is passed by reference
|
||||
var res = await plc.ReadClassAsync(tc2, DB2);
|
||||
tc = (TestClassWithPrivateSetters)res.Item2;
|
||||
Assert.AreEqual(tc.BitVariable00, tc2.BitVariable00);
|
||||
Assert.AreEqual(tc.BitVariable10, tc2.BitVariable10);
|
||||
Assert.AreEqual(tc.DIntVariable, tc2.DIntVariable);
|
||||
Assert.AreEqual(tc.IntVariable, tc2.IntVariable);
|
||||
Assert.AreEqual(tc.LRealVariable, tc2.LRealVariable, 0.1);
|
||||
Assert.AreEqual(tc.RealVariable, tc2.RealVariable);
|
||||
Assert.AreEqual(tc.DWordVariable, tc2.DWordVariable);
|
||||
|
||||
Assert.AreEqual(TestClassWithPrivateSetters.PRIVATE_SETTER_VALUE, tc2.PrivateSetterProperty);
|
||||
Assert.AreEqual(TestClassWithPrivateSetters.PROTECTED_SETTER_VALUE, tc2.ProtectedSetterProperty);
|
||||
Assert.AreEqual(TestClassWithPrivateSetters.INTERNAL_SETTER_VALUE, tc2.InternalSetterProperty);
|
||||
Assert.AreEqual(TestClassWithPrivateSetters.JUST_A_GETTER_VALUE, tc2.JustAGetterProperty);
|
||||
}
|
||||
|
||||
|
||||
[TestMethod]
|
||||
public async Task Test_Async_ReadBytesReturnsNullIfPlcIsNotConnected()
|
||||
{
|
||||
using (var notConnectedPlc = new Plc(CpuType.S7300, "255.255.255.255", 0, 0))
|
||||
{
|
||||
Assert.IsFalse(notConnectedPlc.IsConnected);
|
||||
TestClass tc = new TestClass();
|
||||
await Assert.ThrowsExceptionAsync<PlcException>(async () => await notConnectedPlc.ReadClassAsync(tc, DB2));
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task Test_Async_ReadClassWithGenericReturnsSameResultAsReadClassWithoutGeneric()
|
||||
{
|
||||
Assert.IsTrue(plc.IsConnected, "Before executing this test, the plc must be connected. Check constructor.");
|
||||
|
||||
TestClass tc = new TestClass
|
||||
{
|
||||
BitVariable00 = true,
|
||||
BitVariable10 = true,
|
||||
DIntVariable = -100000,
|
||||
IntVariable = -15000,
|
||||
LRealVariable = -154.789,
|
||||
RealVariable = -154.789f,
|
||||
DWordVariable = 850
|
||||
};
|
||||
|
||||
await plc.WriteClassAsync(tc, DB2);
|
||||
|
||||
// Values that are read from a class are stored inside the class itself, that is passed by reference
|
||||
TestClass tc2 = new TestClass();
|
||||
var res = await plc.ReadClassAsync(tc2, DB2);
|
||||
tc2 = (TestClass)res.Item2;
|
||||
TestClass tc2Generic = await plc.ReadClassAsync<TestClass>(DB2);
|
||||
|
||||
Assert.AreEqual(tc2.BitVariable00, tc2Generic.BitVariable00);
|
||||
Assert.AreEqual(tc2.BitVariable10, tc2Generic.BitVariable10);
|
||||
Assert.AreEqual(tc2.DIntVariable, tc2Generic.DIntVariable);
|
||||
Assert.AreEqual(tc2.IntVariable, tc2Generic.IntVariable);
|
||||
Assert.AreEqual(Math.Round(tc2.LRealVariable, 3), Math.Round(tc2Generic.LRealVariable, 3));
|
||||
Assert.AreEqual(tc2.RealVariable, tc2Generic.RealVariable);
|
||||
Assert.AreEqual(tc2.DWordVariable, tc2Generic.DWordVariable);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task Test_Async_ReadClassWithGenericReturnsNullIfPlcIsNotConnected()
|
||||
{
|
||||
using (var notConnectedPlc = new Plc(CpuType.S7300, "255.255.255.255", 0, 0))
|
||||
{
|
||||
Assert.IsFalse(notConnectedPlc.IsConnected, "Before executing this test, the plc must be connected. Check constructor.");
|
||||
await Assert.ThrowsExceptionAsync<PlcException>(async () => await notConnectedPlc.ReadClassAsync<TestClass>(DB2));
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task Test_Async_ReadClassWithGenericAndClassFactoryReturnsSameResultAsReadClassWithoutGeneric()
|
||||
{
|
||||
Assert.IsTrue(plc.IsConnected, "Before executing this test, the plc must be connected. Check constructor.");
|
||||
|
||||
TestClass tc = new TestClass
|
||||
{
|
||||
BitVariable00 = true,
|
||||
BitVariable10 = true,
|
||||
DIntVariable = -100000,
|
||||
IntVariable = -15000,
|
||||
LRealVariable = -154.789,
|
||||
RealVariable = -154.789f,
|
||||
DWordVariable = 850
|
||||
};
|
||||
|
||||
await plc.WriteClassAsync(tc, DB2);
|
||||
|
||||
// Values that are read from a class are stored inside the class itself, that is passed by reference
|
||||
TestClass tc2Generic = await plc.ReadClassAsync<TestClass>(DB2);
|
||||
TestClass tc2GenericWithClassFactory = await plc.ReadClassAsync(() => new TestClass(), DB2);
|
||||
|
||||
Assert.AreEqual(tc2Generic.BitVariable00, tc2GenericWithClassFactory.BitVariable00);
|
||||
Assert.AreEqual(tc2Generic.BitVariable10, tc2GenericWithClassFactory.BitVariable10);
|
||||
Assert.AreEqual(tc2Generic.DIntVariable, tc2GenericWithClassFactory.DIntVariable);
|
||||
Assert.AreEqual(Math.Round(tc2Generic.LRealVariable, 3), Math.Round(tc2GenericWithClassFactory.LRealVariable, 3));
|
||||
Assert.AreEqual(tc2Generic.RealVariable, tc2GenericWithClassFactory.RealVariable);
|
||||
Assert.AreEqual(tc2Generic.DWordVariable, tc2GenericWithClassFactory.DWordVariable);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task Test_Async_ReadClassWithGenericAndClassFactoryThrowsExceptionPlcIsNotConnected()
|
||||
{
|
||||
using (var notConnectedPlc = new Plc(CpuType.S7300, "255.255.255.255", 0, 0))
|
||||
{
|
||||
Assert.IsFalse(notConnectedPlc.IsConnected);
|
||||
await Assert.ThrowsExceptionAsync<PlcException>(async () => await notConnectedPlc.ReadClassAsync(() => new TestClass(), DB2));
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task Test_Async_ReadClassWithNestedClassAfterBit()
|
||||
{
|
||||
Assert.IsTrue(plc.IsConnected, "Before executing this test, the plc must be connected. Check constructor.");
|
||||
|
||||
Assert.AreEqual(6, Types.Class.GetClassSize(new TestClassWithNestedClass()));
|
||||
|
||||
TestClassWithNestedClass tc = new TestClassWithNestedClass();
|
||||
tc.BitVariable00 = true;
|
||||
tc.BitVariable01.BitVariable00 = true;
|
||||
tc.ByteVariable02.ByteVariable00 = 128;
|
||||
tc.BitVariable03 = true;
|
||||
tc.ShortVariable04.ShortVarialbe00 = -15000;
|
||||
|
||||
TestClassWithNestedClass tc2 = await plc.ReadClassAsync<TestClassWithNestedClass>(DB4);
|
||||
Assert.AreEqual(tc.BitVariable00, tc2.BitVariable00);
|
||||
Assert.AreEqual(tc.BitVariable01.BitVariable00, tc2.BitVariable01.BitVariable00);
|
||||
Assert.AreEqual(tc.ByteVariable02.ByteVariable00, tc2.ByteVariable02.ByteVariable00);
|
||||
Assert.AreEqual(tc.BitVariable03, tc2.BitVariable03);
|
||||
Assert.AreEqual(tc.ShortVariable04.ShortVarialbe00, tc2.ShortVariable04.ShortVarialbe00);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task Test_Async_ReadStructThrowsExceptionPlcIsNotConnected()
|
||||
{
|
||||
using (var notConnectedPlc = new Plc(CpuType.S7300, "255.255.255.255", 0, 0))
|
||||
{
|
||||
Assert.IsFalse(notConnectedPlc.IsConnected);
|
||||
await Assert.ThrowsExceptionAsync<PlcException>(async () => await notConnectedPlc.ReadStructAsync(typeof(TestStruct), DB2));
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task Test_Async_ReadStructWithGenericReturnsSameResultAsReadStructWithoutGeneric()
|
||||
{
|
||||
Assert.IsTrue(plc.IsConnected, "Before executing this test, the plc must be connected. Check constructor.");
|
||||
|
||||
TestStruct ts = new TestStruct
|
||||
{
|
||||
BitVariable00 = true,
|
||||
BitVariable10 = true,
|
||||
DIntVariable = -100000,
|
||||
IntVariable = -15000,
|
||||
LRealVariable = -154.789,
|
||||
RealVariable = -154.789f,
|
||||
DWordVariable = 850,
|
||||
WStringVariable = "ÄÜÉÊéà",
|
||||
StringVariable = "Hallo"
|
||||
};
|
||||
|
||||
plc.WriteStruct(ts, DB2);
|
||||
|
||||
// Values that are read from a struct are stored in a new struct, returned by the funcion ReadStruct
|
||||
TestStruct ts2 = (TestStruct)await plc.ReadStructAsync(typeof(TestStruct), DB2);
|
||||
var test = await plc.ReadStructAsync<TestStruct>(DB2);
|
||||
TestStruct ts2Generic = test.Value;
|
||||
|
||||
Assert.AreEqual(ts2.BitVariable00, ts2Generic.BitVariable00);
|
||||
Assert.AreEqual(ts2.BitVariable10, ts2Generic.BitVariable10);
|
||||
Assert.AreEqual(ts2.DIntVariable, ts2Generic.DIntVariable);
|
||||
Assert.AreEqual(ts2.IntVariable, ts2Generic.IntVariable);
|
||||
Assert.AreEqual(ts2.LRealVariable, ts2Generic.LRealVariable);
|
||||
Assert.AreEqual(ts2.RealVariable, ts2Generic.RealVariable);
|
||||
Assert.AreEqual(ts2.DWordVariable, ts2Generic.DWordVariable);
|
||||
Assert.AreEqual(ts2.WStringVariable, ts2Generic.WStringVariable);
|
||||
Assert.AreEqual(ts2.StringVariable, ts2Generic.StringVariable);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task Test_Async_ReadStructWithGenericThrowsExceptionIfPlcIsNotConnected()
|
||||
{
|
||||
using (var notConnectedPlc = new Plc(CpuType.S7300, "255.255.255.255", 0, 0))
|
||||
{
|
||||
Assert.IsFalse(notConnectedPlc.IsConnected);
|
||||
await Assert.ThrowsExceptionAsync<PlcException>(async () => await notConnectedPlc.ReadStructAsync<TestStruct>(DB2));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tests that the method ReadClass returns the number of bytes read from the plc
|
||||
/// </summary>
|
||||
[TestMethod]
|
||||
public async Task Test_Async_ReadClassReturnsNumberOfReadBytesFromThePlc()
|
||||
{
|
||||
Assert.IsTrue(plc.IsConnected, "Before executing this test, the plc must be connected. Check constructor.");
|
||||
|
||||
TestClass tc = new TestClass
|
||||
{
|
||||
BitVariable00 = true,
|
||||
BitVariable10 = true,
|
||||
DIntVariable = -100000,
|
||||
IntVariable = -15000,
|
||||
LRealVariable = -154.789,
|
||||
RealVariable = -154.789f,
|
||||
DWordVariable = 850
|
||||
};
|
||||
plc.WriteClass(tc, DB2);
|
||||
|
||||
int expectedReadBytes = (int)Types.Class.GetClassSize(tc);
|
||||
|
||||
TestClass tc2 = new TestClass();
|
||||
// Values that are read from a class are stored inside the class itself, that is passed by reference
|
||||
var res = await plc.ReadClassAsync(tc2, DB2);
|
||||
int actualReadBytes = res.Item1;
|
||||
|
||||
Assert.AreEqual(expectedReadBytes, actualReadBytes);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task Test_Async_ReadClassWithArray()
|
||||
{
|
||||
Assert.IsTrue(plc.IsConnected, "Before executing this test, the plc must be connected. Check constructor.");
|
||||
|
||||
TestClassWithArrays tc = new TestClassWithArrays
|
||||
{
|
||||
Bool = true
|
||||
};
|
||||
tc.BoolValues[1] = true;
|
||||
tc.Int = int.MinValue;
|
||||
tc.Ints[0] = int.MinValue;
|
||||
tc.Ints[1] = int.MaxValue;
|
||||
tc.Short = short.MinValue;
|
||||
tc.Shorts[0] = short.MinValue;
|
||||
tc.Shorts[1] = short.MaxValue;
|
||||
tc.Double = float.MinValue;
|
||||
tc.Doubles[0] = float.MinValue + 1;
|
||||
tc.Doubles[1] = float.MaxValue;
|
||||
tc.UShort = ushort.MinValue + 1;
|
||||
tc.UShorts[0] = ushort.MinValue + 1;
|
||||
tc.UShorts[1] = ushort.MaxValue;
|
||||
|
||||
plc.WriteClass(tc, DB2);
|
||||
TestClassWithArrays tc2 = await plc.ReadClassAsync<TestClassWithArrays>(DB2);
|
||||
|
||||
Assert.AreEqual(tc.Bool, tc2.Bool);
|
||||
Assert.AreEqual(tc.BoolValues[0], tc2.BoolValues[0]);
|
||||
Assert.AreEqual(tc.BoolValues[1], tc2.BoolValues[1]);
|
||||
|
||||
Assert.AreEqual(tc.Int, tc2.Int);
|
||||
Assert.AreEqual(tc.Ints[0], tc2.Ints[0]);
|
||||
Assert.AreEqual(tc.Ints[1], tc.Ints[1]);
|
||||
|
||||
Assert.AreEqual(tc.Short, tc2.Short);
|
||||
Assert.AreEqual(tc.Shorts[0], tc2.Shorts[0]);
|
||||
Assert.AreEqual(tc.Shorts[1], tc2.Shorts[1]);
|
||||
|
||||
Assert.AreEqual(tc.Double, tc2.Double);
|
||||
Assert.AreEqual(tc.Doubles[0], tc2.Doubles[0]);
|
||||
Assert.AreEqual(tc.Doubles[1], tc2.Doubles[1]);
|
||||
|
||||
Assert.AreEqual(tc.UShort, tc2.UShort);
|
||||
Assert.AreEqual(tc.UShorts[0], tc2.UShorts[0]);
|
||||
Assert.AreEqual(tc.UShorts[1], tc2.UShorts[1]);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task Test_Async_ReadClassWithArrayAndCustomType()
|
||||
{
|
||||
Assert.IsTrue(plc.IsConnected, "Before executing this test, the plc must be connected. Check constructor.");
|
||||
|
||||
TestClassWithCustomType tc = new TestClassWithCustomType
|
||||
{
|
||||
Int = int.MinValue,
|
||||
CustomType = new CustomType()
|
||||
};
|
||||
tc.CustomType.Bools[1] = true;
|
||||
tc.CustomTypes[0] = new CustomType();
|
||||
tc.CustomTypes[1] = new CustomType();
|
||||
tc.CustomTypes[0].Bools[0] = true;
|
||||
tc.CustomTypes[1].Bools[1] = true;
|
||||
|
||||
plc.WriteClass(tc, DB2);
|
||||
TestClassWithCustomType tc2 = await plc.ReadClassAsync<TestClassWithCustomType>(DB2);
|
||||
|
||||
Assert.AreEqual(tc.Int, tc2.Int);
|
||||
Assert.AreEqual(tc.CustomType.Bools[0], tc2.CustomType.Bools[0]);
|
||||
Assert.AreEqual(tc.CustomType.Bools[1], tc2.CustomType.Bools[1]);
|
||||
Assert.AreEqual(tc.CustomTypes[0].Bools[0], tc2.CustomTypes[0].Bools[0]);
|
||||
Assert.AreEqual(tc.CustomTypes[0].Bools[1], tc2.CustomTypes[0].Bools[1]);
|
||||
Assert.AreEqual(tc.CustomTypes[1].Bools[0], tc2.CustomTypes[1].Bools[0]);
|
||||
Assert.AreEqual(tc.CustomTypes[1].Bools[1], tc2.CustomTypes[1].Bools[1]);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task Test_Async_ReadWriteSingle()
|
||||
{
|
||||
float test_value = 55.6632f;
|
||||
await plc.WriteAsync("DB1.DBD0", test_value);
|
||||
var helper = await plc.ReadAsync("DB1.DBD0");
|
||||
float test_value2 = Conversion.ConvertToFloat((uint)helper);
|
||||
|
||||
Assert.AreEqual(test_value, test_value2, "Compare Write/Read"); //No delta, datatype matches
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task Test_Async_ReadWriteBytesMany()
|
||||
{
|
||||
Assert.IsTrue(plc.IsConnected, "Before executing this test, the plc must be connected. Check constructor.");
|
||||
|
||||
var count = 2000;
|
||||
var dataItems = new List<byte>();
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
dataItems.Add((byte)(i % 256));
|
||||
}
|
||||
|
||||
await plc.WriteBytesAsync(DataType.DataBlock, 2, 0, dataItems.ToArray());
|
||||
|
||||
var res = await plc.ReadBytesAsync(DataType.DataBlock, 2, 0, count);
|
||||
|
||||
for (int x = 0; x < count; x++)
|
||||
{
|
||||
Assert.AreEqual(x % 256, res[x], string.Format("Bit {0} failed", x));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write a large amount of data and test cancellation
|
||||
/// </summary>
|
||||
[TestMethod]
|
||||
public async Task Test_Async_WriteLargeByteArrayWithCancellation()
|
||||
{
|
||||
Assert.IsTrue(plc.IsConnected, "Before executing this test, the plc must be connected. Check constructor.");
|
||||
|
||||
var cancellationSource = new CancellationTokenSource();
|
||||
var cancellationToken = cancellationSource.Token;
|
||||
|
||||
var randomEngine = new Random();
|
||||
var data = new byte[8192];
|
||||
var db = 2;
|
||||
randomEngine.NextBytes(data);
|
||||
|
||||
cancellationSource.CancelAfter(TimeSpan.FromMilliseconds(5));
|
||||
try
|
||||
{
|
||||
await plc.WriteBytesAsync(DataType.DataBlock, db, 0, data, cancellationToken);
|
||||
}
|
||||
catch(TaskCanceledException)
|
||||
{
|
||||
// everything is good, that is the exception we expect
|
||||
Console.WriteLine("Task was cancelled as expected.");
|
||||
return;
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
Assert.Fail($"Wrong exception type received. Expected {typeof(TaskCanceledException)}, received {e.GetType()}.");
|
||||
}
|
||||
|
||||
// Depending on how tests run, this can also just succeed without getting cancelled at all. Do nothing in this case.
|
||||
Console.WriteLine("Task was not cancelled as expected.");
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,8 @@
|
||||
#region Using
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using S7.Net;
|
||||
using S7.Net.UnitTest.Helpers;
|
||||
using S7.Net.UnitTest;
|
||||
using System.ServiceProcess;
|
||||
using S7.Net.Types;
|
||||
using S7.UnitTest.Helpers;
|
||||
|
||||
@@ -30,13 +26,19 @@ using S7.UnitTest.Helpers;
|
||||
* server has problems.
|
||||
*
|
||||
*/
|
||||
|
||||
//This file contains tests for the synchronous methods
|
||||
#pragma warning disable CS0618
|
||||
namespace S7.Net.UnitTest
|
||||
{
|
||||
[TestClass]
|
||||
public class S7NetTests
|
||||
public partial class S7NetTests : IDisposable
|
||||
{
|
||||
#region Constants
|
||||
const int DB2 = 2;
|
||||
const int DB4 = 4;
|
||||
const short TestServerPort = 31122;
|
||||
const string TestServerIp = "127.0.0.1";
|
||||
#endregion
|
||||
|
||||
#region Private fields
|
||||
@@ -49,16 +51,19 @@ namespace S7.Net.UnitTest
|
||||
/// </summary>
|
||||
public S7NetTests()
|
||||
{
|
||||
plc = new Plc(CpuType.S7300, "127.0.0.1", 0, 2);
|
||||
//ConsoleManager.Show();
|
||||
ShutDownServiceS7oiehsx64();
|
||||
plc = CreatePlc();
|
||||
|
||||
}
|
||||
|
||||
private static Plc CreatePlc()
|
||||
{
|
||||
return new Plc(CpuType.S7300, TestServerIp, TestServerPort, 0, 2);
|
||||
}
|
||||
|
||||
[TestInitialize]
|
||||
public void Setup()
|
||||
{
|
||||
S7TestServer.Start();
|
||||
S7TestServer.Start(TestServerPort);
|
||||
plc.Open();
|
||||
}
|
||||
|
||||
@@ -78,8 +83,14 @@ namespace S7.Net.UnitTest
|
||||
{
|
||||
if (plc.IsConnected == false)
|
||||
{
|
||||
var error = plc.Open();
|
||||
Assert.AreEqual(ErrorCode.NoError, error, "If you have s7 installed you must close s7oiehsx64 service.");
|
||||
try
|
||||
{
|
||||
plc.Open();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new Exception("If you have s7 installed you must close s7oiehsx64 service.", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -136,19 +147,24 @@ namespace S7.Net.UnitTest
|
||||
|
||||
/// <summary>
|
||||
/// Read/Write a single REAL with a single request.
|
||||
/// Test that writing a double and reading it gives the correct value.
|
||||
/// Test that writing a float and reading it gives the correct value.
|
||||
/// </summary>
|
||||
[TestMethod]
|
||||
public void T03_WriteAndReadRealVariables()
|
||||
{
|
||||
Assert.IsTrue(plc.IsConnected, "Before executing this test, the plc must be connected. Check constructor.");
|
||||
|
||||
// Reading and writing a double is quite complicated, because it needs to be converted to DWord before the write,
|
||||
// then reconvert to double after the read.
|
||||
double val = 35.687;
|
||||
plc.Write("DB1.DBD40", val.ConvertToUInt());
|
||||
double result = ((uint)plc.Read("DB1.DBD40")).ConvertToDouble();
|
||||
Assert.AreEqual(val, Math.Round(result, 3)); // float lose precision, so i need to round it
|
||||
// Reading and writing a float is quite complicated, because it needs to be converted to DWord before the write,
|
||||
// then reconvert to float after the read. Float values can contain only 7 digits, so no precision is lost.
|
||||
float val2 = 1234567;
|
||||
plc.Write("DB1.DBD40", val2.ConvertToUInt());
|
||||
float result2 = ((uint)plc.Read("DB1.DBD40")).ConvertToFloat();
|
||||
Assert.AreEqual(val2, result2);
|
||||
|
||||
float val3 = 12.34567f;
|
||||
plc.Write("DB1.DBD40", val3.ConvertToUInt());
|
||||
float result3 = ((uint)plc.Read("DB1.DBD40")).ConvertToFloat();
|
||||
Assert.AreEqual(val3, result3);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -164,7 +180,8 @@ namespace S7.Net.UnitTest
|
||||
tc.BitVariable10 = true;
|
||||
tc.DIntVariable = -100000;
|
||||
tc.IntVariable = -15000;
|
||||
tc.RealVariable = -154.789;
|
||||
tc.LRealVariable = -154.789;
|
||||
tc.RealVariable = -154.789f;
|
||||
tc.DWordVariable = 850;
|
||||
plc.WriteClass(tc, DB2);
|
||||
TestClass tc2 = new TestClass();
|
||||
@@ -174,7 +191,8 @@ namespace S7.Net.UnitTest
|
||||
Assert.AreEqual(tc.BitVariable10, tc2.BitVariable10);
|
||||
Assert.AreEqual(tc.DIntVariable, tc2.DIntVariable);
|
||||
Assert.AreEqual(tc.IntVariable, tc2.IntVariable);
|
||||
Assert.AreEqual(tc.RealVariable, Math.Round(tc2.RealVariable, 3));
|
||||
Assert.AreEqual(tc.LRealVariable, tc2.LRealVariable);
|
||||
Assert.AreEqual(tc.RealVariable, tc2.RealVariable);
|
||||
Assert.AreEqual(tc.DWordVariable, tc2.DWordVariable);
|
||||
}
|
||||
|
||||
@@ -191,8 +209,12 @@ namespace S7.Net.UnitTest
|
||||
tc.BitVariable10 = true;
|
||||
tc.DIntVariable = -100000;
|
||||
tc.IntVariable = -15000;
|
||||
tc.RealVariable = -154.789;
|
||||
tc.LRealVariable = -154.789;
|
||||
tc.RealVariable = -154.789f;
|
||||
tc.DWordVariable = 850;
|
||||
tc.WStringVariable = "ÄÜÉÊéà";
|
||||
tc.StringVariable = "Hallo";
|
||||
|
||||
plc.WriteStruct(tc, DB2);
|
||||
// Values that are read from a struct are stored in a new struct, returned by the funcion ReadStruct
|
||||
TestStruct tc2 = (TestStruct)plc.ReadStruct(typeof(TestStruct), DB2);
|
||||
@@ -200,8 +222,11 @@ namespace S7.Net.UnitTest
|
||||
Assert.AreEqual(tc.BitVariable10, tc2.BitVariable10);
|
||||
Assert.AreEqual(tc.DIntVariable, tc2.DIntVariable);
|
||||
Assert.AreEqual(tc.IntVariable, tc2.IntVariable);
|
||||
Assert.AreEqual(tc.RealVariable, Math.Round(tc2.RealVariable, 3));
|
||||
Assert.AreEqual(tc.LRealVariable, tc2.LRealVariable);
|
||||
Assert.AreEqual(tc.RealVariable, tc2.RealVariable);
|
||||
Assert.AreEqual(tc.DWordVariable, tc2.DWordVariable);
|
||||
Assert.AreEqual(tc.WStringVariable, tc2.WStringVariable);
|
||||
Assert.AreEqual(tc.StringVariable, tc2.StringVariable);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -238,30 +263,28 @@ namespace S7.Net.UnitTest
|
||||
tc.IntVariable110 = 200;
|
||||
tc.IntVariable111 = 201;
|
||||
plc.WriteStruct(tc, DB2);
|
||||
Assert.AreEqual(ErrorCode.NoError, plc.LastErrorCode);
|
||||
// Values that are read from a struct are stored in a new struct, returned by the funcion ReadStruct
|
||||
TestLongStruct tc2 = (TestLongStruct)plc.ReadStruct(typeof(TestLongStruct), DB2);
|
||||
Assert.AreEqual(ErrorCode.NoError, plc.LastErrorCode);
|
||||
Assert.AreEqual( tc.IntVariable0, tc2.IntVariable0 );
|
||||
Assert.AreEqual( tc.IntVariable1, tc2.IntVariable1 );
|
||||
Assert.AreEqual( tc.IntVariable10, tc2.IntVariable10);
|
||||
Assert.AreEqual( tc.IntVariable11, tc2.IntVariable11);
|
||||
Assert.AreEqual( tc.IntVariable20, tc2.IntVariable20);
|
||||
Assert.AreEqual( tc.IntVariable21, tc2.IntVariable21);
|
||||
Assert.AreEqual( tc.IntVariable30, tc2.IntVariable30);
|
||||
Assert.AreEqual( tc.IntVariable31, tc2.IntVariable31);
|
||||
Assert.AreEqual( tc.IntVariable40, tc2.IntVariable40);
|
||||
Assert.AreEqual( tc.IntVariable41, tc2.IntVariable41);
|
||||
Assert.AreEqual( tc.IntVariable50, tc2.IntVariable50);
|
||||
Assert.AreEqual( tc.IntVariable51, tc2.IntVariable51);
|
||||
Assert.AreEqual( tc.IntVariable60, tc2.IntVariable60);
|
||||
Assert.AreEqual( tc.IntVariable61, tc2.IntVariable61);
|
||||
Assert.AreEqual( tc.IntVariable70, tc2.IntVariable70);
|
||||
Assert.AreEqual( tc.IntVariable71, tc2.IntVariable71);
|
||||
Assert.AreEqual( tc.IntVariable80, tc2.IntVariable80);
|
||||
Assert.AreEqual( tc.IntVariable81, tc2.IntVariable81);
|
||||
Assert.AreEqual( tc.IntVariable90, tc2.IntVariable90);
|
||||
Assert.AreEqual(tc.IntVariable91, tc2.IntVariable91);
|
||||
Assert.AreEqual(tc.IntVariable0, tc2.IntVariable0);
|
||||
Assert.AreEqual(tc.IntVariable1, tc2.IntVariable1);
|
||||
Assert.AreEqual(tc.IntVariable10, tc2.IntVariable10);
|
||||
Assert.AreEqual(tc.IntVariable11, tc2.IntVariable11);
|
||||
Assert.AreEqual(tc.IntVariable20, tc2.IntVariable20);
|
||||
Assert.AreEqual(tc.IntVariable21, tc2.IntVariable21);
|
||||
Assert.AreEqual(tc.IntVariable30, tc2.IntVariable30);
|
||||
Assert.AreEqual(tc.IntVariable31, tc2.IntVariable31);
|
||||
Assert.AreEqual(tc.IntVariable40, tc2.IntVariable40);
|
||||
Assert.AreEqual(tc.IntVariable41, tc2.IntVariable41);
|
||||
Assert.AreEqual(tc.IntVariable50, tc2.IntVariable50);
|
||||
Assert.AreEqual(tc.IntVariable51, tc2.IntVariable51);
|
||||
Assert.AreEqual(tc.IntVariable60, tc2.IntVariable60);
|
||||
Assert.AreEqual(tc.IntVariable61, tc2.IntVariable61);
|
||||
Assert.AreEqual(tc.IntVariable70, tc2.IntVariable70);
|
||||
Assert.AreEqual(tc.IntVariable71, tc2.IntVariable71);
|
||||
Assert.AreEqual(tc.IntVariable80, tc2.IntVariable80);
|
||||
Assert.AreEqual(tc.IntVariable81, tc2.IntVariable81);
|
||||
Assert.AreEqual(tc.IntVariable90, tc2.IntVariable90);
|
||||
Assert.AreEqual(tc.IntVariable91, tc2.IntVariable91);
|
||||
Assert.AreEqual(tc.IntVariable100, tc2.IntVariable100);
|
||||
Assert.AreEqual(tc.IntVariable101, tc2.IntVariable101);
|
||||
Assert.AreEqual(tc.IntVariable110, tc2.IntVariable110);
|
||||
@@ -302,11 +325,9 @@ namespace S7.Net.UnitTest
|
||||
tc.IntVariable110 = 200;
|
||||
tc.IntVariable111 = 201;
|
||||
plc.WriteClass(tc, DB2);
|
||||
Assert.AreEqual(ErrorCode.NoError, plc.LastErrorCode);
|
||||
// Values that are read from a struct are stored in a new struct, returned by the funcion ReadStruct
|
||||
TestLongClass tc2 = new TestLongClass();
|
||||
plc.ReadClass(tc2, DB2);
|
||||
Assert.AreEqual(ErrorCode.NoError, plc.LastErrorCode);
|
||||
Assert.AreEqual(tc.IntVariable0, tc2.IntVariable0);
|
||||
Assert.AreEqual(tc.IntVariable1, tc2.IntVariable1);
|
||||
Assert.AreEqual(tc.IntVariable10, tc2.IntVariable10);
|
||||
@@ -386,19 +407,51 @@ namespace S7.Net.UnitTest
|
||||
{
|
||||
Assert.IsTrue(plc.IsConnected, "Before executing this test, the plc must be connected. Check constructor.");
|
||||
|
||||
ushort val = 16384;
|
||||
plc.Write("DB2.DBW16384", val);
|
||||
ushort result = (ushort)plc.Read("DB2.DBW16384");
|
||||
Assert.AreEqual(val, result, "A ushort goes from 0 to 64512");
|
||||
bool val = true;
|
||||
plc.Write("DB2.DBX0.5", val);
|
||||
bool result = (bool)plc.Read("DB2.DBX0.5");
|
||||
Assert.AreEqual(val, result);
|
||||
|
||||
ushort val2 = 129;
|
||||
plc.Write("DB2.DBW16", val2);
|
||||
ushort result2 = (ushort)plc.Read("DB2.DBW16");
|
||||
Assert.AreEqual(val2, result2, "A ushort goes from 0 to 64512");
|
||||
ushort val1 = 16384;
|
||||
plc.Write("DB2.DBW16384", val1);
|
||||
ushort result1 = (ushort)plc.Read("DB2.DBW16384");
|
||||
Assert.AreEqual(val1, result1, "A ushort goes from 0 to 64512");
|
||||
|
||||
bool val2 = true;
|
||||
plc.Write("DB2.DBX8192.7", val2);
|
||||
bool result2 = (bool)plc.Read("DB2.DBX8192.7");
|
||||
Assert.AreEqual(val2, result2);
|
||||
|
||||
ushort val3 = 129;
|
||||
plc.Write("DB2.DBW16", val3);
|
||||
ushort result3 = (ushort)plc.Read("DB2.DBW16");
|
||||
Assert.AreEqual(val3, result3, "A ushort goes from 0 to 64512");
|
||||
|
||||
byte[] val4 = new byte[] { 0x12, 0x34 };
|
||||
plc.Write("DB2.DBB2048", val4[0]);
|
||||
plc.Write("DB2.DBB2049", val4[1]);
|
||||
byte result4b0 = (byte)plc.Read("DB2.DBB2048");
|
||||
byte result4b1 = (byte)plc.Read("DB2.DBB2049");
|
||||
Assert.AreEqual(val4[0], result4b0);
|
||||
Assert.AreEqual(val4[1], result4b1);
|
||||
|
||||
bool val6 = true;
|
||||
plc.Write("DB2.DBX16384.6", val6);
|
||||
bool result6 = (bool)plc.Read("DB2.DBX16384.6");
|
||||
Assert.AreEqual(val6, result6);
|
||||
|
||||
var dataItems = new List<DataItem>()
|
||||
{
|
||||
new DataItem
|
||||
{
|
||||
Count = 1,
|
||||
DataType = DataType.DataBlock,
|
||||
DB = 2,
|
||||
StartByteAdr = 0,
|
||||
BitAdr = 5,
|
||||
VarType = VarType.Bit
|
||||
}
|
||||
,new DataItem
|
||||
{
|
||||
Count = 1,
|
||||
DataType = DataType.DataBlock,
|
||||
@@ -407,19 +460,61 @@ namespace S7.Net.UnitTest
|
||||
VarType = VarType.Word
|
||||
},
|
||||
new DataItem
|
||||
{
|
||||
Count = 1,
|
||||
DataType = DataType.DataBlock,
|
||||
DB = 2,
|
||||
StartByteAdr = 8192,
|
||||
BitAdr = 7,
|
||||
VarType = VarType.Bit
|
||||
},
|
||||
new DataItem
|
||||
{
|
||||
Count = 1,
|
||||
DataType = DataType.DataBlock,
|
||||
DB = 2,
|
||||
StartByteAdr = 16,
|
||||
VarType = VarType.Word
|
||||
}
|
||||
},
|
||||
// single byte
|
||||
new DataItem
|
||||
{
|
||||
Count = 1,
|
||||
DataType = DataType.DataBlock,
|
||||
DB = 2,
|
||||
StartByteAdr = 2048,
|
||||
VarType = VarType.Byte
|
||||
},
|
||||
// multiple bytes
|
||||
new DataItem
|
||||
{
|
||||
Count = 2,
|
||||
DataType = DataType.DataBlock,
|
||||
DB = 2,
|
||||
StartByteAdr = 2048,
|
||||
VarType = VarType.Byte
|
||||
},
|
||||
new DataItem
|
||||
{
|
||||
Count = 1,
|
||||
DataType = DataType.DataBlock,
|
||||
DB = 2,
|
||||
StartByteAdr = 16384,
|
||||
BitAdr = 6,
|
||||
VarType = VarType.Bit
|
||||
},
|
||||
};
|
||||
|
||||
plc.ReadMultipleVars(dataItems);
|
||||
|
||||
Assert.AreEqual(dataItems[0].Value, val);
|
||||
Assert.AreEqual(dataItems[1].Value, val2);
|
||||
Assert.AreEqual(dataItems[1].Value, val1);
|
||||
Assert.AreEqual(dataItems[2].Value, val2);
|
||||
Assert.AreEqual(dataItems[3].Value, val3);
|
||||
Assert.AreEqual(dataItems[4].Value, val4[0]);
|
||||
Assert.AreEqual(((byte[])dataItems[5].Value)[0], val4[0]); //dataItem[5].Value should be byte[2]
|
||||
Assert.AreEqual(((byte[])dataItems[5].Value)[1], val4[1]);
|
||||
Assert.AreEqual(dataItems[6].Value, val6);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -455,6 +550,18 @@ namespace S7.Net.UnitTest
|
||||
plc.Write("DB1.DBX0.7", 0);
|
||||
boolVariable = (bool)plc.Read("DB1.DBX0.7");
|
||||
Assert.IsFalse(boolVariable);
|
||||
|
||||
plc.Write("DB1.DBX658.0", 1);
|
||||
boolVariable = (bool)plc.Read("DB1.DBX658.0");
|
||||
Assert.IsTrue(boolVariable);
|
||||
|
||||
plc.Write("DB1.DBX658.7", 1);
|
||||
boolVariable = (bool)plc.Read("DB1.DBX658.7");
|
||||
Assert.IsTrue(boolVariable);
|
||||
|
||||
plc.Write("DB2.DBX9658.0", 1);
|
||||
boolVariable = (bool)plc.Read("DB2.DBX9658.0");
|
||||
Assert.IsTrue(boolVariable);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
@@ -467,7 +574,8 @@ namespace S7.Net.UnitTest
|
||||
tc.BitVariable10 = true;
|
||||
tc.DIntVariable = -100000;
|
||||
tc.IntVariable = -15000;
|
||||
tc.RealVariable = -154.789;
|
||||
tc.LRealVariable = -154.789;
|
||||
tc.RealVariable = -154.789f;
|
||||
tc.DWordVariable = 850;
|
||||
|
||||
plc.WriteClass(tc, DB2);
|
||||
@@ -479,7 +587,8 @@ namespace S7.Net.UnitTest
|
||||
Assert.AreEqual(tc.BitVariable10, tc2.BitVariable10);
|
||||
Assert.AreEqual(tc.DIntVariable, tc2.DIntVariable);
|
||||
Assert.AreEqual(tc.IntVariable, tc2.IntVariable);
|
||||
Assert.AreEqual(tc.RealVariable, Math.Round(tc2.RealVariable, 3));
|
||||
Assert.AreEqual(tc.LRealVariable, tc2.LRealVariable);
|
||||
Assert.AreEqual(tc.RealVariable, tc2.RealVariable);
|
||||
Assert.AreEqual(tc.DWordVariable, tc2.DWordVariable);
|
||||
|
||||
Assert.AreEqual(TestClassWithPrivateSetters.PRIVATE_SETTER_VALUE, tc2.PrivateSetterProperty);
|
||||
@@ -489,19 +598,14 @@ namespace S7.Net.UnitTest
|
||||
}
|
||||
|
||||
|
||||
[TestMethod]
|
||||
public void T13_ReadBytesReturnsEmptyArrayIfPlcIsNotConnected()
|
||||
[TestMethod, ExpectedException(typeof(PlcException))]
|
||||
public void T13_ReadBytesThrowsIfPlcIsNotConnected()
|
||||
{
|
||||
using (var notConnectedPlc = new Plc(CpuType.S7300, "255.255.255.255", 0, 0))
|
||||
{
|
||||
Assert.IsFalse(notConnectedPlc.IsConnected);
|
||||
|
||||
int expectedReadBytes = 0; // 0 bytes, because no connection was established
|
||||
|
||||
TestClass tc = new TestClass();
|
||||
int actualReadBytes = notConnectedPlc.ReadClass(tc, DB2);
|
||||
|
||||
Assert.AreEqual(expectedReadBytes, actualReadBytes);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -515,7 +619,8 @@ namespace S7.Net.UnitTest
|
||||
tc.BitVariable10 = true;
|
||||
tc.DIntVariable = -100000;
|
||||
tc.IntVariable = -15000;
|
||||
tc.RealVariable = -154.789;
|
||||
tc.LRealVariable = -154.789;
|
||||
tc.RealVariable = -154.789f;
|
||||
tc.DWordVariable = 850;
|
||||
|
||||
plc.WriteClass(tc, DB2);
|
||||
@@ -529,12 +634,13 @@ namespace S7.Net.UnitTest
|
||||
Assert.AreEqual(tc2.BitVariable10, tc2Generic.BitVariable10);
|
||||
Assert.AreEqual(tc2.DIntVariable, tc2Generic.DIntVariable);
|
||||
Assert.AreEqual(tc2.IntVariable, tc2Generic.IntVariable);
|
||||
Assert.AreEqual(Math.Round(tc2.RealVariable, 3), Math.Round(tc2Generic.RealVariable, 3));
|
||||
Assert.AreEqual(Math.Round(tc2.LRealVariable, 3), Math.Round(tc2Generic.LRealVariable, 3));
|
||||
Assert.AreEqual(tc2.RealVariable, tc2Generic.RealVariable);
|
||||
Assert.AreEqual(tc2.DWordVariable, tc2Generic.DWordVariable);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void T15_ReadClassWithGenericReturnsNullIfPlcIsNotConnected()
|
||||
[TestMethod, ExpectedException(typeof(PlcException))]
|
||||
public void T15_ReadClassWithGenericThrowsIfPlcIsNotConnected()
|
||||
{
|
||||
using (var notConnectedPlc = new Plc(CpuType.S7300, "255.255.255.255", 0, 0))
|
||||
{
|
||||
@@ -556,7 +662,8 @@ namespace S7.Net.UnitTest
|
||||
tc.BitVariable10 = true;
|
||||
tc.DIntVariable = -100000;
|
||||
tc.IntVariable = -15000;
|
||||
tc.RealVariable = -154.789;
|
||||
tc.LRealVariable = -154.789;
|
||||
tc.RealVariable = -154.789f;
|
||||
tc.DWordVariable = 850;
|
||||
|
||||
plc.WriteClass(tc, DB2);
|
||||
@@ -569,12 +676,13 @@ namespace S7.Net.UnitTest
|
||||
Assert.AreEqual(tc2Generic.BitVariable10, tc2GenericWithClassFactory.BitVariable10);
|
||||
Assert.AreEqual(tc2Generic.DIntVariable, tc2GenericWithClassFactory.DIntVariable);
|
||||
Assert.AreEqual(tc2Generic.IntVariable, tc2GenericWithClassFactory.IntVariable);
|
||||
Assert.AreEqual(Math.Round(tc2Generic.RealVariable, 3), Math.Round(tc2GenericWithClassFactory.RealVariable, 3));
|
||||
Assert.AreEqual(Math.Round(tc2Generic.LRealVariable, 3), Math.Round(tc2GenericWithClassFactory.LRealVariable, 3));
|
||||
Assert.AreEqual(tc2Generic.RealVariable, tc2GenericWithClassFactory.RealVariable);
|
||||
Assert.AreEqual(tc2Generic.DWordVariable, tc2GenericWithClassFactory.DWordVariable);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void T17_ReadClassWithGenericAndClassFactoryReturnsNullIfPlcIsNotConnected()
|
||||
[TestMethod, ExpectedException(typeof(PlcException))]
|
||||
public void T17_ReadClassWithGenericAndClassFactoryThrowsIfPlcIsNotConnected()
|
||||
{
|
||||
using (var notConnectedPlc = new Plc(CpuType.S7300, "255.255.255.255", 0, 0))
|
||||
{
|
||||
@@ -587,7 +695,75 @@ namespace S7.Net.UnitTest
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void T18_ReadStructReturnsNullIfPlcIsNotConnected()
|
||||
public void T31_ReadClassWithNestedClassAfterBit()
|
||||
{
|
||||
Assert.IsTrue(plc.IsConnected, "Before executing this test, the plc must be connected. Check constructor.");
|
||||
|
||||
Assert.AreEqual(6, Types.Class.GetClassSize(new TestClassWithNestedClass()));
|
||||
|
||||
TestClassWithNestedClass tc = new TestClassWithNestedClass();
|
||||
tc.BitVariable00 = true;
|
||||
tc.BitVariable01.BitVariable00 = true;
|
||||
tc.ByteVariable02.ByteVariable00 = 128;
|
||||
tc.BitVariable03 = true;
|
||||
tc.ShortVariable04.ShortVarialbe00 = -15000;
|
||||
|
||||
TestClassWithNestedClass tc2 = new TestClassWithNestedClass();
|
||||
plc.ReadClass(tc2, DB4);
|
||||
Assert.AreEqual(tc.BitVariable00, tc2.BitVariable00);
|
||||
Assert.AreEqual(tc.BitVariable01.BitVariable00, tc2.BitVariable01.BitVariable00);
|
||||
Assert.AreEqual(tc.ByteVariable02.ByteVariable00, tc2.ByteVariable02.ByteVariable00);
|
||||
Assert.AreEqual(tc.BitVariable03, tc2.BitVariable03);
|
||||
Assert.AreEqual(tc.ShortVariable04.ShortVarialbe00, tc2.ShortVariable04.ShortVarialbe00);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void T32_ReadAndWriteNestedClass()
|
||||
{
|
||||
Assert.IsTrue(plc.IsConnected, "Before executing this test, the plc must be connected. Check constructor.");
|
||||
|
||||
TestClassWithNestedClass tc = new TestClassWithNestedClass
|
||||
{
|
||||
BitVariable00 = true,
|
||||
BitVariable01 = new TestClassInnerWithBool { BitVariable00 = true },
|
||||
ByteVariable02 = new TestClassInnerWithByte { ByteVariable00 = 128 },
|
||||
BitVariable03 = true,
|
||||
ShortVariable04 = new TestClassInnerWithShort { ShortVarialbe00 = -15000 }
|
||||
};
|
||||
|
||||
plc.WriteClass(tc, DB4);
|
||||
TestClassWithNestedClass tc2 = new TestClassWithNestedClass();
|
||||
// Values that are read from a class are stored inside the class itself, that is passed by reference
|
||||
plc.ReadClass(tc2, DB4);
|
||||
Assert.AreEqual(tc.BitVariable00, tc2.BitVariable00);
|
||||
Assert.AreEqual(tc.BitVariable01.BitVariable00, tc2.BitVariable01.BitVariable00);
|
||||
Assert.AreEqual(tc.ByteVariable02.ByteVariable00, tc2.ByteVariable02.ByteVariable00);
|
||||
Assert.AreEqual(tc.BitVariable03, tc2.BitVariable03);
|
||||
Assert.AreEqual(tc.ShortVariable04.ShortVarialbe00, tc2.ShortVariable04.ShortVarialbe00);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write/Read a large amount of data to test PDU max
|
||||
/// </summary>
|
||||
[TestMethod]
|
||||
public void T33_WriteLargeByteArray()
|
||||
{
|
||||
Assert.IsTrue(plc.IsConnected, "Before executing this test, the plc must be connected. Check constructor.");
|
||||
|
||||
var randomEngine = new Random();
|
||||
var data = new byte[8192];
|
||||
var db = 2;
|
||||
randomEngine.NextBytes(data);
|
||||
|
||||
plc.WriteBytes(DataType.DataBlock, db, 0, data);
|
||||
|
||||
var readData = plc.ReadBytes(DataType.DataBlock, db, 0, data.Length);
|
||||
|
||||
CollectionAssert.AreEqual(data, readData);
|
||||
}
|
||||
|
||||
[TestMethod, ExpectedException(typeof(PlcException))]
|
||||
public void T18_ReadStructThrowsIfPlcIsNotConnected()
|
||||
{
|
||||
using (var notConnectedPlc = new Plc(CpuType.S7300, "255.255.255.255", 0, 0))
|
||||
{
|
||||
@@ -609,8 +785,11 @@ namespace S7.Net.UnitTest
|
||||
ts.BitVariable10 = true;
|
||||
ts.DIntVariable = -100000;
|
||||
ts.IntVariable = -15000;
|
||||
ts.RealVariable = -154.789;
|
||||
ts.LRealVariable = -154.789;
|
||||
ts.RealVariable = -154.789f;
|
||||
ts.DWordVariable = 850;
|
||||
ts.WStringVariable = "ÄÜÉÊéà";
|
||||
ts.StringVariable = "Hallo";
|
||||
|
||||
plc.WriteStruct(ts, DB2);
|
||||
|
||||
@@ -622,12 +801,15 @@ namespace S7.Net.UnitTest
|
||||
Assert.AreEqual(ts2.BitVariable10, ts2Generic.BitVariable10);
|
||||
Assert.AreEqual(ts2.DIntVariable, ts2Generic.DIntVariable);
|
||||
Assert.AreEqual(ts2.IntVariable, ts2Generic.IntVariable);
|
||||
Assert.AreEqual(Math.Round(ts2.RealVariable, 3), Math.Round(ts2Generic.RealVariable, 3));
|
||||
Assert.AreEqual(ts2.LRealVariable, ts2Generic.LRealVariable);
|
||||
Assert.AreEqual(ts2.RealVariable, ts2Generic.RealVariable);
|
||||
Assert.AreEqual(ts2.DWordVariable, ts2Generic.DWordVariable);
|
||||
Assert.AreEqual(ts2.WStringVariable, ts2Generic.WStringVariable);
|
||||
Assert.AreEqual(ts2.StringVariable, ts2Generic.StringVariable);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void T20_ReadStructWithGenericReturnsNullIfPlcIsNotConnected()
|
||||
[TestMethod, ExpectedException(typeof(PlcException))]
|
||||
public void T20_ReadStructThrowsIfPlcIsNotConnected()
|
||||
{
|
||||
using (var notConnectedPlc = new Plc(CpuType.S7300, "255.255.255.255", 0, 0))
|
||||
{
|
||||
@@ -652,11 +834,12 @@ namespace S7.Net.UnitTest
|
||||
tc.BitVariable10 = true;
|
||||
tc.DIntVariable = -100000;
|
||||
tc.IntVariable = -15000;
|
||||
tc.RealVariable = -154.789;
|
||||
tc.LRealVariable = -154.789;
|
||||
tc.RealVariable = -154.789f;
|
||||
tc.DWordVariable = 850;
|
||||
plc.WriteClass(tc, DB2);
|
||||
|
||||
int expectedReadBytes = Types.Class.GetClassSize(tc);
|
||||
int expectedReadBytes = (int)Types.Class.GetClassSize(tc);
|
||||
|
||||
TestClass tc2 = new TestClass();
|
||||
// Values that are read from a class are stored inside the class itself, that is passed by reference
|
||||
@@ -664,8 +847,8 @@ namespace S7.Net.UnitTest
|
||||
|
||||
Assert.AreEqual(expectedReadBytes, actualReadBytes);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
|
||||
[TestMethod]
|
||||
public void T22_ReadClassWithArray()
|
||||
{
|
||||
Assert.IsTrue(plc.IsConnected, "Before executing this test, the plc must be connected. Check constructor.");
|
||||
@@ -682,6 +865,9 @@ namespace S7.Net.UnitTest
|
||||
tc.Double = float.MinValue;
|
||||
tc.Doubles[0] = float.MinValue + 1;
|
||||
tc.Doubles[1] = float.MaxValue;
|
||||
tc.Single = float.MinValue;
|
||||
tc.Singles[0] = float.MinValue + 1;
|
||||
tc.Singles[1] = float.MaxValue;
|
||||
tc.UShort = ushort.MinValue + 1;
|
||||
tc.UShorts[0] = ushort.MinValue + 1;
|
||||
tc.UShorts[1] = ushort.MaxValue;
|
||||
@@ -705,6 +891,10 @@ namespace S7.Net.UnitTest
|
||||
Assert.AreEqual(tc.Doubles[0], tc2.Doubles[0]);
|
||||
Assert.AreEqual(tc.Doubles[1], tc2.Doubles[1]);
|
||||
|
||||
Assert.AreEqual(tc.Single, tc2.Single);
|
||||
Assert.AreEqual(tc.Singles[0], tc2.Singles[0]);
|
||||
Assert.AreEqual(tc.Singles[1], tc2.Singles[1]);
|
||||
|
||||
Assert.AreEqual(tc.UShort, tc2.UShort);
|
||||
Assert.AreEqual(tc.UShorts[0], tc2.UShorts[0]);
|
||||
Assert.AreEqual(tc.UShorts[1], tc2.UShorts[1]);
|
||||
@@ -743,7 +933,14 @@ namespace S7.Net.UnitTest
|
||||
S7TestServer.Stop();
|
||||
|
||||
var unreachablePlc = new Plc(CpuType.S7300, "255.255.255.255", 0, 2);
|
||||
Assert.IsFalse(unreachablePlc.IsAvailable);
|
||||
try
|
||||
{
|
||||
unreachablePlc.Open();
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
Assert.IsFalse(unreachablePlc.IsConnected);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
@@ -751,31 +948,137 @@ namespace S7.Net.UnitTest
|
||||
{
|
||||
plc.Close();
|
||||
S7TestServer.Stop();
|
||||
S7TestServer.Start();
|
||||
S7TestServer.Start(TestServerPort);
|
||||
|
||||
var reachablePlc = new Plc(CpuType.S7300, "127.0.0.1", 0, 2);
|
||||
Assert.IsTrue(reachablePlc.IsAvailable);
|
||||
var reachablePlc = CreatePlc();
|
||||
reachablePlc.Open();
|
||||
Assert.IsTrue(reachablePlc.IsConnected);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void T26_ReadWriteDouble()
|
||||
{
|
||||
double test_value = 55.66;
|
||||
plc.Write(DataType.DataBlock, 1, 0, test_value);
|
||||
var result = (double)plc.Read(DataType.DataBlock, 1, 0, VarType.LReal, 1);
|
||||
|
||||
Assert.AreEqual(test_value, result, "Compare Write/Read");
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void T27_ReadWriteBytesMany()
|
||||
{
|
||||
Assert.IsTrue(plc.IsConnected, "Before executing this test, the plc must be connected. Check constructor.");
|
||||
|
||||
var count = 2000;
|
||||
var dataItems = new List<byte>();
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
dataItems.Add((byte)(i % 256));
|
||||
}
|
||||
|
||||
plc.WriteBytes(DataType.DataBlock, 2, 0, dataItems.ToArray());
|
||||
|
||||
var res = plc.ReadBytes(DataType.DataBlock, 2, 0, count);
|
||||
|
||||
for (int x = 0; x < count; x++)
|
||||
{
|
||||
Assert.AreEqual(x % 256, res[x], $"Mismatch at offset {x}, expected {x % 256}, actual {res[x]}.");
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void T28_ReadClass_DoesntCrash_When_ReadingLessThan1Byte()
|
||||
{
|
||||
Assert.IsTrue(plc.IsConnected, "Before executing this test, the plc must be connected. Check constructor.");
|
||||
|
||||
var tc = new TestSmallClass
|
||||
{
|
||||
Bool1 = true
|
||||
};
|
||||
|
||||
plc.WriteClass(tc, DB2);
|
||||
var tc2 = plc.ReadClass<TestSmallClass>(DB2);
|
||||
|
||||
Assert.AreEqual(tc.Bool1, tc2.Bool1);
|
||||
}
|
||||
|
||||
[TestMethod, ExpectedException(typeof(PlcException))]
|
||||
public void T29_Read_Write_ThrowsWhenPlcIsNotReachable()
|
||||
{
|
||||
// leave plc Open
|
||||
S7TestServer.Stop();
|
||||
|
||||
double test_value = 55.66;
|
||||
plc.Write("DB1.DBD0", test_value);
|
||||
|
||||
var helper = plc.Read("DB1.DBD0");
|
||||
Assert.AreEqual(helper, null, "Value in Read.");
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void T30_ReadWriteSingle()
|
||||
{
|
||||
float test_value = 55.6632f;
|
||||
plc.Write("DB1.DBD0", test_value);
|
||||
var helper = plc.Read("DB1.DBD0");
|
||||
float test_value2 = Conversion.ConvertToFloat((uint)helper);
|
||||
|
||||
Assert.AreEqual(test_value, test_value2, "Compare Write/Read"); //No delta, datatype matches
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void T33_ReadWriteDateTimeLong()
|
||||
{
|
||||
var test_value = System.DateTime.Now;
|
||||
var db = 1;
|
||||
var offset = 0;
|
||||
|
||||
plc.WriteBytes(DataType.DataBlock, db, offset, Types.DateTimeLong.ToByteArray(test_value));
|
||||
var test_value2 = plc.Read(DataType.DataBlock, db, offset, VarType.DateTimeLong, 1);
|
||||
Assert.IsInstanceOfType(test_value2, typeof(System.DateTime));
|
||||
|
||||
Assert.AreEqual(test_value, test_value2, "Compare DateTimeLong Write/Read");
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private methods
|
||||
|
||||
private static void ShutDownServiceS7oiehsx64()
|
||||
#region IDisposable Support
|
||||
private bool disposedValue = false; // To detect redundant calls
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
try
|
||||
if (!disposedValue)
|
||||
{
|
||||
ServiceController sc = new ServiceController("s7oiehsx64");
|
||||
switch (sc.Status)
|
||||
if (disposing)
|
||||
{
|
||||
case ServiceControllerStatus.Running:
|
||||
sc.Stop();
|
||||
break;
|
||||
plc.Close();
|
||||
}
|
||||
|
||||
// TODO: free unmanaged resources (unmanaged objects) and override a finalizer below.
|
||||
// TODO: set large fields to null.
|
||||
|
||||
disposedValue = true;
|
||||
}
|
||||
catch { } // service not found
|
||||
}
|
||||
|
||||
// TODO: override a finalizer only if Dispose(bool disposing) above has code to free unmanaged resources.
|
||||
// ~S7NetTests() {
|
||||
// // Do not change this code. Put cleanup code in Dispose(bool disposing) above.
|
||||
// Dispose(false);
|
||||
// }
|
||||
|
||||
// This code added to correctly implement the disposable pattern.
|
||||
public void Dispose()
|
||||
{
|
||||
// Do not change this code. Put cleanup code in Dispose(bool disposing) above.
|
||||
Dispose(true);
|
||||
// TODO: uncomment the following line if the finalizer is overridden above.
|
||||
// GC.SuppressFinalize(this);
|
||||
}
|
||||
#endregion
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -36,11 +36,8 @@ namespace Snap7
|
||||
|
||||
public class S7Consts
|
||||
{
|
||||
#if __MonoCS__ // Assuming that we are using Unix release of Mono (otherwise modify it)
|
||||
public const string Snap7LibName = "libsnap7.so";
|
||||
#else
|
||||
public const string Snap7LibName = "snap7.dll";
|
||||
#endif
|
||||
public const string Snap7LibName = "snap7";
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// PARAMS LIST
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
98
S7.Net.UnitTest/StreamTests.cs
Normal file
98
S7.Net.UnitTest/StreamTests.cs
Normal file
@@ -0,0 +1,98 @@
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace S7.Net.UnitTest
|
||||
{
|
||||
/// <summary>
|
||||
/// Test stream which only gives 1 byte per read.
|
||||
/// </summary>
|
||||
class TestStream1BytePerRead : Stream
|
||||
{
|
||||
public TestStream1BytePerRead(byte[] data)
|
||||
{
|
||||
Data = data;
|
||||
}
|
||||
public override bool CanRead => _position < Data.Length;
|
||||
|
||||
public override bool CanSeek => throw new NotImplementedException();
|
||||
|
||||
public override bool CanWrite => throw new NotImplementedException();
|
||||
|
||||
public override long Length => throw new NotImplementedException();
|
||||
|
||||
public override long Position { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
|
||||
public byte[] Data { get; }
|
||||
|
||||
public override void Flush()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
int _position = 0;
|
||||
public override int Read(byte[] buffer, int offset, int count)
|
||||
{
|
||||
if (_position >= Data.Length)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
buffer[offset] = Data[_position];
|
||||
++_position;
|
||||
return 1;
|
||||
}
|
||||
|
||||
public override long Seek(long offset, SeekOrigin origin)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override void SetLength(long value)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override void Write(byte[] buffer, int offset, int count)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// These tests are intended to test <see cref="StreamExtensions"/> functions and other stream-related special cases.
|
||||
/// </summary>
|
||||
[TestClass]
|
||||
public class StreamTests
|
||||
{
|
||||
public TestContext TestContext { get; set; }
|
||||
|
||||
[TestMethod]
|
||||
public async Task TPKT_ReadRestrictedStreamAsync()
|
||||
{
|
||||
var fullMessage = ProtocolUnitTest.StringToByteArray("0300002902f0803203000000010002001400000401ff0400807710000100000103000000033f8ccccd");
|
||||
var m = new TestStream1BytePerRead(fullMessage);
|
||||
var t = await TPKT.ReadAsync(m, TestContext.CancellationTokenSource.Token);
|
||||
Assert.AreEqual(fullMessage.Length, t.Length);
|
||||
Assert.AreEqual(fullMessage.Last(), t.Data.Last());
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TPKT_ReadRestrictedStream()
|
||||
{
|
||||
var fullMessage = ProtocolUnitTest.StringToByteArray("0300002902f0803203000000010002001400000401ff0400807710000100000103000000033f8ccccd");
|
||||
var m = new TestStream1BytePerRead(fullMessage);
|
||||
var t = TPKT.Read(m);
|
||||
Assert.AreEqual(fullMessage.Length, t.Length);
|
||||
Assert.AreEqual(fullMessage.Last(), t.Data.Last());
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TPKT_ReadStreamTooShort()
|
||||
{
|
||||
var fullMessage = ProtocolUnitTest.StringToByteArray("0300002902f0803203000000010002001400");
|
||||
var m = new TestStream1BytePerRead(fullMessage);
|
||||
Assert.ThrowsException<TPKTInvalidException>(() => TPKT.Read(m));
|
||||
}
|
||||
}
|
||||
}
|
||||
33
S7.Net.UnitTest/TypeTests/ClassTests.cs
Normal file
33
S7.Net.UnitTest/TypeTests/ClassTests.cs
Normal file
@@ -0,0 +1,33 @@
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using S7.Net.Types;
|
||||
|
||||
namespace S7.Net.UnitTest.TypeTests
|
||||
{
|
||||
[TestClass]
|
||||
public class ClassTests
|
||||
{
|
||||
[TestMethod]
|
||||
public void GetClassSizeTest()
|
||||
{
|
||||
Assert.AreEqual(Class.GetClassSize(new TestClassUnevenSize(1, 1)), 6);
|
||||
Assert.AreEqual(Class.GetClassSize(new TestClassUnevenSize(2, 15)), 6);
|
||||
Assert.AreEqual(Class.GetClassSize(new TestClassUnevenSize(2, 16)), 6);
|
||||
Assert.AreEqual(Class.GetClassSize(new TestClassUnevenSize(2, 17)), 8);
|
||||
Assert.AreEqual(Class.GetClassSize(new TestClassUnevenSize(3, 15)), 8);
|
||||
Assert.AreEqual(Class.GetClassSize(new TestClassUnevenSize(3, 17)), 10);
|
||||
}
|
||||
|
||||
private class TestClassUnevenSize
|
||||
{
|
||||
public bool Bool { get; set; }
|
||||
public byte[] Bytes { get; set; }
|
||||
public bool[] Bools { get; set; }
|
||||
|
||||
public TestClassUnevenSize(int byteCount, int bitCount)
|
||||
{
|
||||
Bytes = new byte[byteCount];
|
||||
Bools = new bool[bitCount];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
171
S7.Net.UnitTest/TypeTests/DateTimeLongTests.cs
Normal file
171
S7.Net.UnitTest/TypeTests/DateTimeLongTests.cs
Normal file
@@ -0,0 +1,171 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
|
||||
namespace S7.Net.UnitTest.TypeTests
|
||||
{
|
||||
public static class DateTimeLongTests
|
||||
{
|
||||
private static readonly DateTime SampleDateTime = new DateTime(1993, 12, 25, 8, 12, 34, 567);
|
||||
|
||||
private static readonly byte[] SampleByteArray = {0x07, 0xC9, 0x0C, 0x19, 0x07, 0x08, 0x0C, 0x22, 0x21, 0xCB, 0xBB, 0xC0 };
|
||||
|
||||
private static readonly byte[] SpecMinByteArray =
|
||||
{
|
||||
0x07, 0xB2, 0x01, 0x01, (byte) (int) (Types.DateTimeLong.SpecMinimumDateTime.DayOfWeek + 1), 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
};
|
||||
|
||||
private static readonly byte[] SpecMaxByteArray =
|
||||
{
|
||||
0x08, 0xD6, 0x04, 0x0B, (byte) (int) (Types.DateTimeLong.SpecMaximumDateTime.DayOfWeek + 1), 0x17, 0x2F, 0x10, 0x32, 0xE7, 0x01, 0x80
|
||||
};
|
||||
|
||||
[TestClass]
|
||||
public class FromByteArray
|
||||
{
|
||||
[TestMethod]
|
||||
public void Sample()
|
||||
{
|
||||
AssertFromByteArrayEquals(SampleDateTime, SampleByteArray);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void SpecMinimum()
|
||||
{
|
||||
AssertFromByteArrayEquals(Types.DateTimeLong.SpecMinimumDateTime, SpecMinByteArray);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void SpecMaximum()
|
||||
{
|
||||
AssertFromByteArrayEquals(Types.DateTimeLong.SpecMaximumDateTime, SpecMaxByteArray);
|
||||
}
|
||||
|
||||
[TestMethod, ExpectedException(typeof(ArgumentOutOfRangeException))]
|
||||
public void ThrowsOnLessThan12Bytes()
|
||||
{
|
||||
Types.DateTimeLong.FromByteArray(new byte[11]);
|
||||
}
|
||||
|
||||
[TestMethod, ExpectedException(typeof(ArgumentOutOfRangeException))]
|
||||
public void ThrowsOnMoreTHan12Bytes()
|
||||
{
|
||||
Types.DateTimeLong.FromByteArray(new byte[13]);
|
||||
}
|
||||
|
||||
[TestMethod, ExpectedException(typeof(ArgumentOutOfRangeException))]
|
||||
public void ThrowsOnInvalidYear()
|
||||
{
|
||||
Types.DateTimeLong.FromByteArray(MutateSample(0, 0xa0));
|
||||
}
|
||||
|
||||
[TestMethod, ExpectedException(typeof(ArgumentOutOfRangeException))]
|
||||
public void ThrowsOnZeroMonth()
|
||||
{
|
||||
Types.DateTimeLong.FromByteArray(MutateSample(2, 0x00));
|
||||
}
|
||||
|
||||
[TestMethod, ExpectedException(typeof(ArgumentOutOfRangeException))]
|
||||
public void ThrowsOnTooLargeMonth()
|
||||
{
|
||||
Types.DateTimeLong.FromByteArray(MutateSample(2, 0x13));
|
||||
}
|
||||
|
||||
[TestMethod, ExpectedException(typeof(ArgumentOutOfRangeException))]
|
||||
public void ThrowsOnZeroDay()
|
||||
{
|
||||
Types.DateTimeLong.FromByteArray(MutateSample(3, 0x00));
|
||||
}
|
||||
|
||||
[TestMethod, ExpectedException(typeof(ArgumentOutOfRangeException))]
|
||||
public void ThrowsOnTooLargeDay()
|
||||
{
|
||||
Types.DateTimeLong.FromByteArray(MutateSample(3, 0x32));
|
||||
}
|
||||
|
||||
[TestMethod, ExpectedException(typeof(ArgumentOutOfRangeException))]
|
||||
public void ThrowsOnInvalidHour()
|
||||
{
|
||||
Types.DateTimeLong.FromByteArray(MutateSample(5, 0x24));
|
||||
}
|
||||
|
||||
[TestMethod, ExpectedException(typeof(ArgumentOutOfRangeException))]
|
||||
public void ThrowsOnInvalidMinute()
|
||||
{
|
||||
Types.DateTimeLong.FromByteArray(MutateSample(6, 0x60));
|
||||
}
|
||||
|
||||
[TestMethod, ExpectedException(typeof(ArgumentOutOfRangeException))]
|
||||
public void ThrowsOnInvalidSecond()
|
||||
{
|
||||
Types.DateTimeLong.FromByteArray(MutateSample(7, 0x60));
|
||||
}
|
||||
|
||||
[TestMethod, ExpectedException(typeof(ArgumentOutOfRangeException))]
|
||||
public void ThrowsOnInvalidNanosecondsFirstDigit()
|
||||
{
|
||||
Types.DateTimeLong.FromByteArray(MutateSample(8, 0x3B));
|
||||
}
|
||||
|
||||
|
||||
[TestMethod, ExpectedException(typeof(ArgumentOutOfRangeException))]
|
||||
public void ThrowsOnZeroDayOfWeek()
|
||||
{
|
||||
Types.DateTimeLong.FromByteArray(MutateSample(4, 0));
|
||||
}
|
||||
|
||||
[TestMethod, ExpectedException(typeof(ArgumentOutOfRangeException))]
|
||||
public void ThrowsOnTooLargeDayOfWeek()
|
||||
{
|
||||
Types.DateTimeLong.FromByteArray(MutateSample(4, 8));
|
||||
}
|
||||
|
||||
private static void AssertFromByteArrayEquals(DateTime expected, params byte[] bytes)
|
||||
{
|
||||
Assert.AreEqual(expected, Types.DateTimeLong.FromByteArray(bytes));
|
||||
}
|
||||
|
||||
private static byte[] MutateSample(int index, byte value) =>
|
||||
SampleByteArray.Select((b, i) => i == index ? value : b).ToArray();
|
||||
}
|
||||
|
||||
[TestClass]
|
||||
public class ToByteArray
|
||||
{
|
||||
[TestMethod]
|
||||
public void Sample()
|
||||
{
|
||||
AssertToByteArrayEquals(SampleDateTime, SampleByteArray);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void SpecMinimum()
|
||||
{
|
||||
AssertToByteArrayEquals(Types.DateTimeLong.SpecMinimumDateTime, SpecMinByteArray);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void SpecMaximum()
|
||||
{
|
||||
AssertToByteArrayEquals(Types.DateTimeLong.SpecMaximumDateTime, SpecMaxByteArray);
|
||||
}
|
||||
|
||||
[TestMethod, ExpectedException(typeof(ArgumentOutOfRangeException))]
|
||||
public void ThrowsOnTimeBeforeSpecMinimum()
|
||||
{
|
||||
Types.DateTimeLong.ToByteArray(new DateTime(1950, 1, 1));
|
||||
}
|
||||
|
||||
[TestMethod, ExpectedException(typeof(ArgumentOutOfRangeException))]
|
||||
public void ThrowsOnTimeAfterSpecMaximum()
|
||||
{
|
||||
Types.DateTimeLong.ToByteArray(new DateTime(2790, 1, 1));
|
||||
}
|
||||
|
||||
private static void AssertToByteArrayEquals(DateTime value, params byte[] expected)
|
||||
{
|
||||
CollectionAssert.AreEqual(expected, Types.DateTimeLong.ToByteArray(value));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
176
S7.Net.UnitTest/TypeTests/DateTimeTests.cs
Normal file
176
S7.Net.UnitTest/TypeTests/DateTimeTests.cs
Normal file
@@ -0,0 +1,176 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
|
||||
namespace S7.Net.UnitTest.TypeTests
|
||||
{
|
||||
public static class DateTimeTests
|
||||
{
|
||||
private static readonly DateTime SampleDateTime = new DateTime(1993, 12, 25, 8, 12, 34, 567);
|
||||
|
||||
private static readonly byte[] SampleByteArray = {0x93, 0x12, 0x25, 0x08, 0x12, 0x34, 0x56, 7 << 4 | 7};
|
||||
|
||||
private static readonly byte[] SpecMinByteArray =
|
||||
{
|
||||
0x90, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, (byte) (int) (Types.DateTime.SpecMinimumDateTime.DayOfWeek + 1)
|
||||
};
|
||||
|
||||
private static readonly byte[] SpecMaxByteArray =
|
||||
{
|
||||
0x89, 0x12, 0x31, 0x23, 0x59, 0x59, 0x99, (byte) (9 << 4 | (int) (Types.DateTime.SpecMaximumDateTime.DayOfWeek + 1))
|
||||
};
|
||||
|
||||
[TestClass]
|
||||
public class FromByteArray
|
||||
{
|
||||
[TestMethod]
|
||||
public void Sample()
|
||||
{
|
||||
AssertFromByteArrayEquals(SampleDateTime, SampleByteArray);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void SpecMinimum()
|
||||
{
|
||||
AssertFromByteArrayEquals(Types.DateTime.SpecMinimumDateTime, SpecMinByteArray);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void SpecMaximum()
|
||||
{
|
||||
AssertFromByteArrayEquals(Types.DateTime.SpecMaximumDateTime, SpecMaxByteArray);
|
||||
}
|
||||
|
||||
[TestMethod, ExpectedException(typeof(ArgumentOutOfRangeException))]
|
||||
public void ThrowsOnLessThan8Bytes()
|
||||
{
|
||||
Types.DateTime.FromByteArray(new byte[7]);
|
||||
}
|
||||
|
||||
[TestMethod, ExpectedException(typeof(ArgumentOutOfRangeException))]
|
||||
public void ThrowsOnMoreTHan8Bytes()
|
||||
{
|
||||
Types.DateTime.FromByteArray(new byte[9]);
|
||||
}
|
||||
|
||||
[TestMethod, ExpectedException(typeof(ArgumentOutOfRangeException))]
|
||||
public void ThrowsOnInvalidYear()
|
||||
{
|
||||
Types.DateTime.FromByteArray(MutateSample(0, 0xa0));
|
||||
}
|
||||
|
||||
[TestMethod, ExpectedException(typeof(ArgumentOutOfRangeException))]
|
||||
public void ThrowsOnZeroMonth()
|
||||
{
|
||||
Types.DateTime.FromByteArray(MutateSample(1, 0x00));
|
||||
}
|
||||
|
||||
[TestMethod, ExpectedException(typeof(ArgumentOutOfRangeException))]
|
||||
public void ThrowsOnTooLargeMonth()
|
||||
{
|
||||
Types.DateTime.FromByteArray(MutateSample(1, 0x13));
|
||||
}
|
||||
|
||||
[TestMethod, ExpectedException(typeof(ArgumentOutOfRangeException))]
|
||||
public void ThrowsOnZeroDay()
|
||||
{
|
||||
Types.DateTime.FromByteArray(MutateSample(2, 0x00));
|
||||
}
|
||||
|
||||
[TestMethod, ExpectedException(typeof(ArgumentOutOfRangeException))]
|
||||
public void ThrowsOnTooLargeDay()
|
||||
{
|
||||
Types.DateTime.FromByteArray(MutateSample(2, 0x32));
|
||||
}
|
||||
|
||||
[TestMethod, ExpectedException(typeof(ArgumentOutOfRangeException))]
|
||||
public void ThrowsOnInvalidHour()
|
||||
{
|
||||
Types.DateTime.FromByteArray(MutateSample(3, 0x24));
|
||||
}
|
||||
|
||||
[TestMethod, ExpectedException(typeof(ArgumentOutOfRangeException))]
|
||||
public void ThrowsOnInvalidMinute()
|
||||
{
|
||||
Types.DateTime.FromByteArray(MutateSample(4, 0x60));
|
||||
}
|
||||
|
||||
[TestMethod, ExpectedException(typeof(ArgumentOutOfRangeException))]
|
||||
public void ThrowsOnInvalidSecond()
|
||||
{
|
||||
Types.DateTime.FromByteArray(MutateSample(5, 0x60));
|
||||
}
|
||||
|
||||
[TestMethod, ExpectedException(typeof(ArgumentOutOfRangeException))]
|
||||
public void ThrowsOnInvalidFirstTwoMillisecondDigits()
|
||||
{
|
||||
Types.DateTime.FromByteArray(MutateSample(6, 0xa0));
|
||||
}
|
||||
|
||||
[TestMethod, ExpectedException(typeof(ArgumentOutOfRangeException))]
|
||||
public void ThrowsOnInvalidThirdMillisecondDigit()
|
||||
{
|
||||
Types.DateTime.FromByteArray(MutateSample(7, 10 << 4));
|
||||
}
|
||||
|
||||
[TestMethod, ExpectedException(typeof(ArgumentOutOfRangeException))]
|
||||
public void ThrowsOnZeroDayOfWeek()
|
||||
{
|
||||
Types.DateTime.FromByteArray(MutateSample(7, 0));
|
||||
}
|
||||
|
||||
[TestMethod, ExpectedException(typeof(ArgumentOutOfRangeException))]
|
||||
public void ThrowsOnTooLargeDayOfWeek()
|
||||
{
|
||||
Types.DateTime.FromByteArray(MutateSample(7, 8));
|
||||
}
|
||||
|
||||
private static void AssertFromByteArrayEquals(DateTime expected, params byte[] bytes)
|
||||
{
|
||||
Assert.AreEqual(expected, Types.DateTime.FromByteArray(bytes));
|
||||
}
|
||||
|
||||
private static byte[] MutateSample(int index, byte value) =>
|
||||
SampleByteArray.Select((b, i) => i == index ? value : b).ToArray();
|
||||
}
|
||||
|
||||
[TestClass]
|
||||
public class ToByteArray
|
||||
{
|
||||
[TestMethod]
|
||||
public void Sample()
|
||||
{
|
||||
AssertToByteArrayEquals(SampleDateTime, SampleByteArray);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void SpecMinimum()
|
||||
{
|
||||
AssertToByteArrayEquals(Types.DateTime.SpecMinimumDateTime, SpecMinByteArray);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void SpecMaximum()
|
||||
{
|
||||
AssertToByteArrayEquals(Types.DateTime.SpecMaximumDateTime, SpecMaxByteArray);
|
||||
}
|
||||
|
||||
[TestMethod, ExpectedException(typeof(ArgumentOutOfRangeException))]
|
||||
public void ThrowsOnTimeBeforeSpecMinimum()
|
||||
{
|
||||
Types.DateTime.ToByteArray(new DateTime(1970, 1, 1));
|
||||
}
|
||||
|
||||
[TestMethod, ExpectedException(typeof(ArgumentOutOfRangeException))]
|
||||
public void ThrowsOnTimeAfterSpecMaximum()
|
||||
{
|
||||
Types.DateTime.ToByteArray(new DateTime(2090, 1, 1));
|
||||
}
|
||||
|
||||
private static void AssertToByteArrayEquals(DateTime value, params byte[] expected)
|
||||
{
|
||||
CollectionAssert.AreEqual(expected, Types.DateTime.ToByteArray(value));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
152
S7.Net.UnitTest/TypeTests/S7StringTests.cs
Normal file
152
S7.Net.UnitTest/TypeTests/S7StringTests.cs
Normal file
@@ -0,0 +1,152 @@
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using S7.Net.Types;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Linq;
|
||||
|
||||
namespace S7.Net.UnitTest.TypeTests
|
||||
{
|
||||
[TestClass]
|
||||
public class S7StringTests
|
||||
{
|
||||
[TestMethod]
|
||||
public void ReadEmptyStringWithZeroByteLength()
|
||||
{
|
||||
AssertFromByteArrayEquals("", 0, 0);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void ReadEmptyStringWithOneByteLength()
|
||||
{
|
||||
AssertFromByteArrayEquals("", 1, 0, 0);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void ReadEmptyStringWithOneByteGarbage()
|
||||
{
|
||||
AssertFromByteArrayEquals("", 1, 0, (byte) 'a');
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void ReadMalformedStringTooShort()
|
||||
{
|
||||
Assert.ThrowsException<PlcException>(() => AssertFromByteArrayEquals("", 1));
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void ReadMalformedStringSizeLargerThanCapacity()
|
||||
{
|
||||
Assert.ThrowsException<PlcException>(() => S7String.FromByteArray(new byte[] { 3, 5, 0, 1, 2 }));
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void ReadMalformedStringCapacityTooLarge()
|
||||
{
|
||||
Assert.ThrowsException<ArgumentException>(() => AssertToByteArrayAndBackEquals("", 300, 0));
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void ReadA()
|
||||
{
|
||||
AssertFromByteArrayEquals("A", 1, 1, (byte) 'A');
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void ReadAbc()
|
||||
{
|
||||
AssertFromByteArrayEquals("Abc", 3, 3, (byte) 'A', (byte) 'b', (byte) 'c');
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void WriteNullWithReservedLengthZero()
|
||||
{
|
||||
Assert.ThrowsException<ArgumentNullException>(() => AssertToByteArrayAndBackEquals(null, 0, 0, 0));
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void WriteEmptyStringWithReservedLengthZero()
|
||||
{
|
||||
AssertToByteArrayAndBackEquals("", 0, 0, 0);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void WriteAWithReservedLengthZero()
|
||||
{
|
||||
AssertToByteArrayAndBackEquals("", 0, 0, 0);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void WriteNullWithReservedLengthOne()
|
||||
{
|
||||
Assert.ThrowsException<ArgumentNullException>(() => AssertToByteArrayAndBackEquals(null, 1, 1, 0));
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void WriteEmptyStringWithReservedLengthOne()
|
||||
{
|
||||
AssertToByteArrayAndBackEquals("", 1, 1, 0, 0);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void WriteAWithReservedLengthOne()
|
||||
{
|
||||
AssertToByteArrayAndBackEquals("A", 1, 1, 1, (byte) 'A');
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void WriteAWithReservedLengthTwo()
|
||||
{
|
||||
AssertToByteArrayAndBackEquals("A", 2, 2, 1, (byte) 'A', 0);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void WriteAbcWithStringLargerThanReservedLength()
|
||||
{
|
||||
Assert.ThrowsException<ArgumentException>(() => S7String.ToByteArray("Abc", 2));
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void WriteAbcWithReservedLengthThree()
|
||||
{
|
||||
AssertToByteArrayAndBackEquals("Abc", 3, 3, 3, (byte) 'A', (byte) 'b', (byte) 'c');
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void WriteAbcWithReservedLengthFour()
|
||||
{
|
||||
AssertToByteArrayAndBackEquals("Abc", 4, 4, 3, (byte) 'A', (byte) 'b', (byte) 'c', 0);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void OddS7StringByteLength()
|
||||
{
|
||||
AssertVarTypeToByteLength(VarType.S7String, 1, 4);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void EvenS7StringByteLength()
|
||||
{
|
||||
AssertVarTypeToByteLength(VarType.S7String, 2, 4);
|
||||
}
|
||||
|
||||
private static void AssertFromByteArrayEquals(string expected, params byte[] bytes)
|
||||
{
|
||||
var convertedString = S7String.FromByteArray(bytes);
|
||||
Assert.AreEqual(expected, convertedString);
|
||||
}
|
||||
|
||||
private static void AssertToByteArrayAndBackEquals(string value, int reservedLength, params byte[] expected)
|
||||
{
|
||||
var convertedData = S7String.ToByteArray(value, reservedLength);
|
||||
CollectionAssert.AreEqual(expected, convertedData);
|
||||
var convertedBack = S7String.FromByteArray(convertedData);
|
||||
Assert.AreEqual(value, convertedBack);
|
||||
}
|
||||
|
||||
private void AssertVarTypeToByteLength(VarType varType, int count, int expectedByteLength)
|
||||
{
|
||||
var byteLength = Plc.VarTypeToByteLength(varType, count);
|
||||
Assert.AreEqual(expectedByteLength, byteLength);
|
||||
}
|
||||
}
|
||||
}
|
||||
151
S7.Net.UnitTest/TypeTests/S7WStringTests.cs
Normal file
151
S7.Net.UnitTest/TypeTests/S7WStringTests.cs
Normal file
@@ -0,0 +1,151 @@
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using S7.Net.Types;
|
||||
using System;
|
||||
|
||||
namespace S7.Net.UnitTest.TypeTests
|
||||
{
|
||||
[TestClass]
|
||||
public class S7WStringTests
|
||||
{
|
||||
[TestMethod]
|
||||
public void ReadEmptyStringWithZeroLength()
|
||||
{
|
||||
AssertFromByteArrayEquals("", 0, 0 , 0, 0);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void ReadEmptyStringWithOneCharLength()
|
||||
{
|
||||
AssertFromByteArrayEquals("", 0, 1, 0, 0, 0, 0);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void ReadEmptyStringWithOneCharGarbage()
|
||||
{
|
||||
|
||||
AssertFromByteArrayEquals("", 0, 1, 0, 0, 0x00, 0x41);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void ReadMalformedStringTooShort()
|
||||
{
|
||||
Assert.ThrowsException<PlcException>(() => AssertFromByteArrayEquals("", 0, 1));
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void ReadMalformedStringSizeLargerThanCapacity()
|
||||
{
|
||||
Assert.ThrowsException<PlcException>(() => S7WString.FromByteArray(new byte[] { 0, 3, 0, 5, 0, 0x00, 0x41, 0x00, 0x41, 0x00, 0x41}));
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void ReadMalformedStringCapacityTooLarge()
|
||||
{
|
||||
Assert.ThrowsException<ArgumentException>(() => AssertToByteArrayAndBackEquals("", 20000, 0));
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void ReadA()
|
||||
{
|
||||
AssertFromByteArrayEquals("A", 0, 1, 0, 1, 0x00, 0x41);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void ReadAbc()
|
||||
{
|
||||
AssertFromByteArrayEquals("Abc", 0, 3, 0, 3, 0x00, 0x41, 0x00, 0x62, 0x00, 0x63);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void WriteNullWithReservedLengthZero()
|
||||
{
|
||||
Assert.ThrowsException<ArgumentNullException>(() => AssertToByteArrayAndBackEquals(null, 0, 0, 0, 0, 0));
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void WriteEmptyStringWithReservedLengthZero()
|
||||
{
|
||||
AssertToByteArrayAndBackEquals("", 0, 0, 0, 0, 0);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void WriteAWithReservedLengthZero()
|
||||
{
|
||||
AssertToByteArrayAndBackEquals("", 0, 0, 0, 0, 0);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void WriteNullWithReservedLengthOne()
|
||||
{
|
||||
Assert.ThrowsException<ArgumentNullException>(() => AssertToByteArrayAndBackEquals(null, 1, 0, 1 , 0, 0));
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void WriteEmptyStringWithReservedLengthOne()
|
||||
{
|
||||
AssertToByteArrayAndBackEquals("", 1, 0, 1, 0, 0, 0, 0);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void WriteAWithReservedLengthOne()
|
||||
{
|
||||
AssertToByteArrayAndBackEquals("A", 1, 0, 1, 0, 1, 0x00, 0x41);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void WriteAWithReservedLengthTwo()
|
||||
{
|
||||
AssertToByteArrayAndBackEquals("A", 2, 0, 2, 0, 1, 0x00, 0x41, 0, 0);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void WriteAbcWithStringLargerThanReservedLength()
|
||||
{
|
||||
Assert.ThrowsException<ArgumentException>(() => S7WString.ToByteArray("Abc", 2));
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void WriteAbcWithReservedLengthThree()
|
||||
{
|
||||
AssertToByteArrayAndBackEquals("Abc", 3, 0, 3, 0, 3, 0x00, 0x41, 0x00, 0x62, 0x00, 0x63);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void WriteAbcWithReservedLengthFour()
|
||||
{
|
||||
AssertToByteArrayAndBackEquals("Abc", 4, 0, 4, 0, 3, 0x00, 0x41, 0x00, 0x62, 0x00, 0x63, 0 , 0);
|
||||
}
|
||||
|
||||
private static void AssertFromByteArrayEquals(string expected, params byte[] bytes)
|
||||
{
|
||||
var convertedString = S7WString.FromByteArray(bytes);
|
||||
Assert.AreEqual(expected, convertedString);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void OddS7WStringByteLength()
|
||||
{
|
||||
AssertVarTypeToByteLength(VarType.S7WString, 1, 6);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void EvenS7WStringByteLength()
|
||||
{
|
||||
AssertVarTypeToByteLength(VarType.S7WString, 2, 8);
|
||||
}
|
||||
|
||||
private static void AssertToByteArrayAndBackEquals(string value, int reservedLength, params byte[] expected)
|
||||
{
|
||||
var convertedData = S7WString.ToByteArray(value, reservedLength);
|
||||
CollectionAssert.AreEqual(expected, convertedData);
|
||||
var convertedBack = S7WString.FromByteArray(convertedData);
|
||||
Assert.AreEqual(value, convertedBack);
|
||||
}
|
||||
|
||||
private void AssertVarTypeToByteLength(VarType varType, int count, int expectedByteLength)
|
||||
{
|
||||
var byteLength = Plc.VarTypeToByteLength(varType, count);
|
||||
Assert.AreEqual(expectedByteLength, byteLength);
|
||||
}
|
||||
}
|
||||
}
|
||||
85
S7.Net.UnitTest/TypeTests/StringTests.cs
Normal file
85
S7.Net.UnitTest/TypeTests/StringTests.cs
Normal file
@@ -0,0 +1,85 @@
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using S7.Net.Types;
|
||||
|
||||
namespace S7.Net.UnitTest.TypeTests
|
||||
{
|
||||
[TestClass]
|
||||
public class StringTests
|
||||
{
|
||||
[TestMethod]
|
||||
public void WriteNullWIthReservedLengthZero()
|
||||
{
|
||||
AssertToByteArrayEquals(null, 0);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void WriteEmptyStringWithReservedLengthZero()
|
||||
{
|
||||
AssertToByteArrayEquals("", 0);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void WriteAWithReservedLengthZero()
|
||||
{
|
||||
AssertToByteArrayEquals("A", 0);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void WriteNullWithReservedLengthOne()
|
||||
{
|
||||
AssertToByteArrayEquals(null, 1, 0);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void WriteEmptyStringWithReservedLengthOne()
|
||||
{
|
||||
AssertToByteArrayEquals("", 1, 0);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void WriteAWithReservedLengthOne()
|
||||
{
|
||||
AssertToByteArrayEquals("A", 1, (byte) 'A');
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void WriteAWithReservedLengthTwo()
|
||||
{
|
||||
AssertToByteArrayEquals("A", 2, (byte) 'A', 0);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void WriteAbcWithReservedLengthOne()
|
||||
{
|
||||
AssertToByteArrayEquals("Abc", 1, (byte) 'A');
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void WriteAbcWithReservedLengthTwo()
|
||||
{
|
||||
AssertToByteArrayEquals("Abc", 2, (byte) 'A', (byte) 'b');
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void WriteAbcWithReservedLengthThree()
|
||||
{
|
||||
AssertToByteArrayEquals("Abc", 3, (byte) 'A', (byte) 'b', (byte) 'c');
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void WriteAbcWithReservedLengthFour()
|
||||
{
|
||||
AssertToByteArrayEquals("Abc", 4, (byte) 'A', (byte) 'b', (byte) 'c', 0);
|
||||
}
|
||||
|
||||
private static void AssertFromByteArrayEquals(string expected, params byte[] bytes)
|
||||
{
|
||||
Assert.AreEqual(expected, String.FromByteArray(bytes));
|
||||
}
|
||||
|
||||
private static void AssertToByteArrayEquals(string value, int reservedLength, params byte[] expected)
|
||||
{
|
||||
CollectionAssert.AreEqual(expected, String.ToByteArray(value, reservedLength));
|
||||
}
|
||||
}
|
||||
}
|
||||
BIN
S7.Net.UnitTest/runtimes/win-x64/native/snap7.dll
Normal file
BIN
S7.Net.UnitTest/runtimes/win-x64/native/snap7.dll
Normal file
Binary file not shown.
Binary file not shown.
164
S7.Net/COTP.cs
Normal file
164
S7.Net/COTP.cs
Normal file
@@ -0,0 +1,164 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace S7.Net
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// COTP Protocol functions and types
|
||||
/// </summary>
|
||||
internal class COTP
|
||||
{
|
||||
public enum PduType : byte
|
||||
{
|
||||
Data = 0xf0,
|
||||
ConnectionConfirmed = 0xd0
|
||||
}
|
||||
/// <summary>
|
||||
/// Describes a COTP TPDU (Transport protocol data unit)
|
||||
/// </summary>
|
||||
public class TPDU
|
||||
{
|
||||
public TPKT TPkt { get; }
|
||||
public byte HeaderLength;
|
||||
public PduType PDUType;
|
||||
public int TPDUNumber;
|
||||
public byte[] Data;
|
||||
public bool LastDataUnit;
|
||||
|
||||
public TPDU(TPKT tPKT)
|
||||
{
|
||||
TPkt = tPKT;
|
||||
|
||||
HeaderLength = tPKT.Data[0]; // Header length excluding this length byte
|
||||
if (HeaderLength >= 2)
|
||||
{
|
||||
PDUType = (PduType)tPKT.Data[1];
|
||||
if (PDUType == PduType.Data) //DT Data
|
||||
{
|
||||
var flags = tPKT.Data[2];
|
||||
TPDUNumber = flags & 0x7F;
|
||||
LastDataUnit = (flags & 0x80) > 0;
|
||||
Data = new byte[tPKT.Data.Length - HeaderLength - 1]; // substract header length byte + header length.
|
||||
Array.Copy(tPKT.Data, HeaderLength + 1, Data, 0, Data.Length);
|
||||
return;
|
||||
}
|
||||
//TODO: Handle other PDUTypes
|
||||
}
|
||||
Data = new byte[0];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads COTP TPDU (Transport protocol data unit) from the network stream
|
||||
/// See: https://tools.ietf.org/html/rfc905
|
||||
/// </summary>
|
||||
/// <param name="stream">The socket to read from</param>
|
||||
/// <returns>COTP DPDU instance</returns>
|
||||
public static TPDU Read(Stream stream)
|
||||
{
|
||||
var tpkt = TPKT.Read(stream);
|
||||
if (tpkt.Length == 0)
|
||||
{
|
||||
throw new TPDUInvalidException("No protocol data received");
|
||||
}
|
||||
return new TPDU(tpkt);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads COTP TPDU (Transport protocol data unit) from the network stream
|
||||
/// See: https://tools.ietf.org/html/rfc905
|
||||
/// </summary>
|
||||
/// <param name="stream">The socket to read from</param>
|
||||
/// <returns>COTP DPDU instance</returns>
|
||||
public static async Task<TPDU> ReadAsync(Stream stream, CancellationToken cancellationToken)
|
||||
{
|
||||
var tpkt = await TPKT.ReadAsync(stream, cancellationToken).ConfigureAwait(false);
|
||||
if (tpkt.Length == 0)
|
||||
{
|
||||
throw new TPDUInvalidException("No protocol data received");
|
||||
}
|
||||
return new TPDU(tpkt);
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return string.Format("Length: {0} PDUType: {1} TPDUNumber: {2} Last: {3} Segment Data: {4}",
|
||||
HeaderLength,
|
||||
PDUType,
|
||||
TPDUNumber,
|
||||
LastDataUnit,
|
||||
BitConverter.ToString(Data)
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Describes a COTP TSDU (Transport service data unit). One TSDU consist of 1 ore more TPDUs
|
||||
/// </summary>
|
||||
public class TSDU
|
||||
{
|
||||
/// <summary>
|
||||
/// Reads the full COTP TSDU (Transport service data unit)
|
||||
/// See: https://tools.ietf.org/html/rfc905
|
||||
/// </summary>
|
||||
/// <param name="stream">The stream to read from</param>
|
||||
/// <returns>Data in TSDU</returns>
|
||||
public static byte[] Read(Stream stream)
|
||||
{
|
||||
var segment = TPDU.Read(stream);
|
||||
|
||||
if (segment.LastDataUnit)
|
||||
{
|
||||
return segment.Data;
|
||||
}
|
||||
|
||||
// More segments are expected, prepare a buffer to store all data
|
||||
var buffer = new byte[segment.Data.Length];
|
||||
Array.Copy(segment.Data, buffer, segment.Data.Length);
|
||||
|
||||
while (!segment.LastDataUnit)
|
||||
{
|
||||
segment = TPDU.Read(stream);
|
||||
var previousLength = buffer.Length;
|
||||
Array.Resize(ref buffer, buffer.Length + segment.Data.Length);
|
||||
Array.Copy(segment.Data, 0, buffer, previousLength, segment.Data.Length);
|
||||
}
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads the full COTP TSDU (Transport service data unit)
|
||||
/// See: https://tools.ietf.org/html/rfc905
|
||||
/// </summary>
|
||||
/// <param name="stream">The stream to read from</param>
|
||||
/// <returns>Data in TSDU</returns>
|
||||
public static async Task<byte[]> ReadAsync(Stream stream, CancellationToken cancellationToken)
|
||||
{
|
||||
var segment = await TPDU.ReadAsync(stream, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
if (segment.LastDataUnit)
|
||||
{
|
||||
return segment.Data;
|
||||
}
|
||||
|
||||
// More segments are expected, prepare a buffer to store all data
|
||||
var buffer = new byte[segment.Data.Length];
|
||||
Array.Copy(segment.Data, buffer, segment.Data.Length);
|
||||
|
||||
while (!segment.LastDataUnit)
|
||||
{
|
||||
segment = await TPDU.ReadAsync(stream, cancellationToken).ConfigureAwait(false);
|
||||
var previousLength = buffer.Length;
|
||||
Array.Resize(ref buffer, buffer.Length + segment.Data.Length);
|
||||
Array.Copy(segment.Data, 0, buffer, previousLength, segment.Data.Length);
|
||||
}
|
||||
|
||||
return buffer;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
19
S7.Net/Compat/TcpClientMixins.cs
Normal file
19
S7.Net/Compat/TcpClientMixins.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
using System.Net.Sockets;
|
||||
|
||||
namespace S7.Net
|
||||
{
|
||||
public static class TcpClientMixins
|
||||
{
|
||||
#if NETSTANDARD1_3
|
||||
public static void Close(this TcpClient tcpClient)
|
||||
{
|
||||
tcpClient.Dispose();
|
||||
}
|
||||
|
||||
public static void Connect(this TcpClient tcpClient, string host, int port)
|
||||
{
|
||||
tcpClient.ConnectAsync(host, port).GetAwaiter().GetResult();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -15,15 +15,11 @@ namespace S7.Net
|
||||
/// <returns></returns>
|
||||
public static int BinStringToInt32(this string txt)
|
||||
{
|
||||
int cnt = 0;
|
||||
int ret = 0;
|
||||
|
||||
for (cnt = txt.Length - 1; cnt >= 0; cnt += -1)
|
||||
for (int i = 0; i < txt.Length; i++)
|
||||
{
|
||||
if (int.Parse(txt.Substring(cnt, 1)) == 1)
|
||||
{
|
||||
ret += (int)(Math.Pow(2, (txt.Length - 1 - cnt)));
|
||||
}
|
||||
ret = (ret << 1) | ((txt[i] == '1') ? 1 : 0);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
@@ -35,20 +31,7 @@ namespace S7.Net
|
||||
/// <returns></returns>
|
||||
public static byte? BinStringToByte(this string txt)
|
||||
{
|
||||
int cnt = 0;
|
||||
int ret = 0;
|
||||
|
||||
if (txt.Length == 8)
|
||||
{
|
||||
for (cnt = 7; cnt >= 0; cnt += -1)
|
||||
{
|
||||
if (int.Parse(txt.Substring(cnt, 1)) == 1)
|
||||
{
|
||||
ret += (int)(Math.Pow(2, (txt.Length - 1 - cnt)));
|
||||
}
|
||||
}
|
||||
return (byte)ret;
|
||||
}
|
||||
if (txt.Length == 8) return (byte)BinStringToInt32(txt);
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -147,7 +130,7 @@ namespace S7.Net
|
||||
}
|
||||
return txt;
|
||||
}
|
||||
catch
|
||||
catch
|
||||
{
|
||||
return "";
|
||||
}
|
||||
@@ -217,26 +200,26 @@ namespace S7.Net
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts from double to DWord (DBD)
|
||||
/// Converts from float to DWord (DBD)
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
public static UInt32 ConvertToUInt(this double input)
|
||||
public static UInt32 ConvertToUInt(this float input)
|
||||
{
|
||||
uint output;
|
||||
output = S7.Net.Types.DWord.FromByteArray(S7.Net.Types.Double.ToByteArray(input));
|
||||
output = S7.Net.Types.DWord.FromByteArray(S7.Net.Types.Real.ToByteArray(input));
|
||||
return output;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts from DWord (DBD) to double
|
||||
/// Converts from DWord (DBD) to float
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
public static double ConvertToDouble(this uint input)
|
||||
public static float ConvertToFloat(this uint input)
|
||||
{
|
||||
double output;
|
||||
output = S7.Net.Types.Double.FromByteArray(S7.Net.Types.DWord.ToByteArray(input));
|
||||
float output;
|
||||
output = S7.Net.Types.Real.FromByteArray(S7.Net.Types.DWord.ToByteArray(input));
|
||||
return output;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,11 @@
|
||||
/// </summary>
|
||||
S7200 = 0,
|
||||
|
||||
/// <summary>
|
||||
/// Siemens Logo 0BA8
|
||||
/// </summary>
|
||||
Logo0BA8 = 1,
|
||||
|
||||
/// <summary>
|
||||
/// S7 300 cpu type
|
||||
/// </summary>
|
||||
@@ -159,10 +164,25 @@
|
||||
Real,
|
||||
|
||||
/// <summary>
|
||||
/// String variable type (variable)
|
||||
/// LReal variable type (64 bits, 8 bytes)
|
||||
/// </summary>
|
||||
LReal,
|
||||
|
||||
/// <summary>
|
||||
/// Char Array / C-String variable type (variable)
|
||||
/// </summary>
|
||||
String,
|
||||
|
||||
/// <summary>
|
||||
/// S7 String variable type (variable)
|
||||
/// </summary>
|
||||
S7String,
|
||||
|
||||
/// <summary>
|
||||
/// S7 WString variable type (variable)
|
||||
/// </summary>
|
||||
S7WString,
|
||||
|
||||
/// <summary>
|
||||
/// Timer variable type
|
||||
/// </summary>
|
||||
@@ -171,6 +191,16 @@
|
||||
/// <summary>
|
||||
/// Counter variable type
|
||||
/// </summary>
|
||||
Counter
|
||||
Counter,
|
||||
|
||||
/// <summary>
|
||||
/// DateTIme variable type
|
||||
/// </summary>
|
||||
DateTime,
|
||||
|
||||
/// <summary>
|
||||
/// DateTimeLong variable type
|
||||
/// </summary>
|
||||
DateTimeLong
|
||||
}
|
||||
}
|
||||
|
||||
18
S7.Net/Helper/MemoryStreamExtension.cs
Normal file
18
S7.Net/Helper/MemoryStreamExtension.cs
Normal file
@@ -0,0 +1,18 @@
|
||||
|
||||
namespace S7.Net.Helper
|
||||
{
|
||||
internal static class MemoryStreamExtension
|
||||
{
|
||||
/// <summary>
|
||||
/// Helper function to write to whole content of the given byte array to a memory stream.
|
||||
///
|
||||
/// Writes all bytes in value from 0 to value.Length to the memory stream.
|
||||
/// </summary>
|
||||
/// <param name="stream"></param>
|
||||
/// <param name="value"></param>
|
||||
public static void WriteByteArray(this System.IO.MemoryStream stream, byte[] value)
|
||||
{
|
||||
stream.Write(value, 0, value.Length);
|
||||
}
|
||||
}
|
||||
}
|
||||
43
S7.Net/InvalidDataException.cs
Normal file
43
S7.Net/InvalidDataException.cs
Normal file
@@ -0,0 +1,43 @@
|
||||
using System;
|
||||
|
||||
namespace S7.Net
|
||||
{
|
||||
#if NET_FULL
|
||||
[Serializable]
|
||||
#endif
|
||||
public class InvalidDataException : Exception
|
||||
{
|
||||
public byte[] ReceivedData { get; }
|
||||
public int ErrorIndex { get; }
|
||||
public byte ExpectedValue { get; }
|
||||
|
||||
public InvalidDataException(string message, byte[] receivedData, int errorIndex, byte expectedValue)
|
||||
: base(FormatMessage(message, receivedData, errorIndex, expectedValue))
|
||||
{
|
||||
ReceivedData = receivedData;
|
||||
ErrorIndex = errorIndex;
|
||||
ExpectedValue = expectedValue;
|
||||
}
|
||||
|
||||
#if NET_FULL
|
||||
protected InvalidDataException(System.Runtime.Serialization.SerializationInfo info,
|
||||
System.Runtime.Serialization.StreamingContext context) : base(info, context)
|
||||
{
|
||||
ReceivedData = (byte[]) info.GetValue(nameof(ReceivedData), typeof(byte[]));
|
||||
ErrorIndex = info.GetInt32(nameof(ErrorIndex));
|
||||
ExpectedValue = info.GetByte(nameof(ExpectedValue));
|
||||
}
|
||||
#endif
|
||||
|
||||
private static string FormatMessage(string message, byte[] receivedData, int errorIndex, byte expectedValue)
|
||||
{
|
||||
if (errorIndex >= receivedData.Length)
|
||||
throw new ArgumentOutOfRangeException(nameof(errorIndex),
|
||||
$"{nameof(errorIndex)} {errorIndex} is outside the bounds of {nameof(receivedData)} with length {receivedData.Length}.");
|
||||
|
||||
return $"{message} Invalid data received. Expected '{expectedValue}' at index {errorIndex}, " +
|
||||
$"but received {receivedData[errorIndex]}. See the {nameof(ReceivedData)} property " +
|
||||
"for the full message received.";
|
||||
}
|
||||
}
|
||||
}
|
||||
1380
S7.Net/PLC.cs
1380
S7.Net/PLC.cs
File diff suppressed because it is too large
Load Diff
207
S7.Net/PLCAddress.cs
Normal file
207
S7.Net/PLCAddress.cs
Normal file
@@ -0,0 +1,207 @@
|
||||
namespace S7.Net
|
||||
{
|
||||
internal class PLCAddress
|
||||
{
|
||||
private DataType dataType;
|
||||
private int dbNumber;
|
||||
private int startByte;
|
||||
private int bitNumber;
|
||||
private VarType varType;
|
||||
|
||||
public DataType DataType
|
||||
{
|
||||
get => dataType;
|
||||
set => dataType = value;
|
||||
}
|
||||
|
||||
public int DbNumber
|
||||
{
|
||||
get => dbNumber;
|
||||
set => dbNumber = value;
|
||||
}
|
||||
|
||||
public int StartByte
|
||||
{
|
||||
get => startByte;
|
||||
set => startByte = value;
|
||||
}
|
||||
|
||||
public int BitNumber
|
||||
{
|
||||
get => bitNumber;
|
||||
set => bitNumber = value;
|
||||
}
|
||||
|
||||
public VarType VarType
|
||||
{
|
||||
get => varType;
|
||||
set => varType = value;
|
||||
}
|
||||
|
||||
public PLCAddress(string address)
|
||||
{
|
||||
Parse(address, out dataType, out dbNumber, out varType, out startByte, out bitNumber);
|
||||
}
|
||||
|
||||
public static void Parse(string input, out DataType dataType, out int dbNumber, out VarType varType, out int address, out int bitNumber)
|
||||
{
|
||||
bitNumber = -1;
|
||||
dbNumber = 0;
|
||||
|
||||
switch (input.Substring(0, 2))
|
||||
{
|
||||
case "DB":
|
||||
string[] strings = input.Split(new char[] { '.' });
|
||||
if (strings.Length < 2)
|
||||
throw new InvalidAddressException("To few periods for DB address");
|
||||
|
||||
dataType = DataType.DataBlock;
|
||||
dbNumber = int.Parse(strings[0].Substring(2));
|
||||
address = int.Parse(strings[1].Substring(3));
|
||||
|
||||
string dbType = strings[1].Substring(0, 3);
|
||||
switch (dbType)
|
||||
{
|
||||
case "DBB":
|
||||
varType = VarType.Byte;
|
||||
return;
|
||||
case "DBW":
|
||||
varType = VarType.Word;
|
||||
return;
|
||||
case "DBD":
|
||||
varType = VarType.DWord;
|
||||
return;
|
||||
case "DBX":
|
||||
bitNumber = int.Parse(strings[2]);
|
||||
if (bitNumber > 7)
|
||||
throw new InvalidAddressException("Bit can only be 0-7");
|
||||
varType = VarType.Bit;
|
||||
return;
|
||||
default:
|
||||
throw new InvalidAddressException();
|
||||
}
|
||||
case "IB":
|
||||
case "EB":
|
||||
// Input byte
|
||||
dataType = DataType.Input;
|
||||
dbNumber = 0;
|
||||
address = int.Parse(input.Substring(2));
|
||||
varType = VarType.Byte;
|
||||
return;
|
||||
case "IW":
|
||||
case "EW":
|
||||
// Input word
|
||||
dataType = DataType.Input;
|
||||
dbNumber = 0;
|
||||
address = int.Parse(input.Substring(2));
|
||||
varType = VarType.Word;
|
||||
return;
|
||||
case "ID":
|
||||
case "ED":
|
||||
// Input double-word
|
||||
dataType = DataType.Input;
|
||||
dbNumber = 0;
|
||||
address = int.Parse(input.Substring(2));
|
||||
varType = VarType.DWord;
|
||||
return;
|
||||
case "QB":
|
||||
case "AB":
|
||||
case "OB":
|
||||
// Output byte
|
||||
dataType = DataType.Output;
|
||||
dbNumber = 0;
|
||||
address = int.Parse(input.Substring(2));
|
||||
varType = VarType.Byte;
|
||||
return;
|
||||
case "QW":
|
||||
case "AW":
|
||||
case "OW":
|
||||
// Output word
|
||||
dataType = DataType.Output;
|
||||
dbNumber = 0;
|
||||
address = int.Parse(input.Substring(2));
|
||||
varType = VarType.Word;
|
||||
return;
|
||||
case "QD":
|
||||
case "AD":
|
||||
case "OD":
|
||||
// Output double-word
|
||||
dataType = DataType.Output;
|
||||
dbNumber = 0;
|
||||
address = int.Parse(input.Substring(2));
|
||||
varType = VarType.DWord;
|
||||
return;
|
||||
case "MB":
|
||||
// Memory byte
|
||||
dataType = DataType.Memory;
|
||||
dbNumber = 0;
|
||||
address = int.Parse(input.Substring(2));
|
||||
varType = VarType.Byte;
|
||||
return;
|
||||
case "MW":
|
||||
// Memory word
|
||||
dataType = DataType.Memory;
|
||||
dbNumber = 0;
|
||||
address = int.Parse(input.Substring(2));
|
||||
varType = VarType.Word;
|
||||
return;
|
||||
case "MD":
|
||||
// Memory double-word
|
||||
dataType = DataType.Memory;
|
||||
dbNumber = 0;
|
||||
address = int.Parse(input.Substring(2));
|
||||
varType = VarType.DWord;
|
||||
return;
|
||||
default:
|
||||
switch (input.Substring(0, 1))
|
||||
{
|
||||
case "E":
|
||||
case "I":
|
||||
// Input
|
||||
dataType = DataType.Input;
|
||||
varType = VarType.Bit;
|
||||
break;
|
||||
case "Q":
|
||||
case "A":
|
||||
case "O":
|
||||
// Output
|
||||
dataType = DataType.Output;
|
||||
varType = VarType.Bit;
|
||||
break;
|
||||
case "M":
|
||||
// Memory
|
||||
dataType = DataType.Memory;
|
||||
varType = VarType.Bit;
|
||||
break;
|
||||
case "T":
|
||||
// Timer
|
||||
dataType = DataType.Timer;
|
||||
dbNumber = 0;
|
||||
address = int.Parse(input.Substring(1));
|
||||
varType = VarType.Timer;
|
||||
return;
|
||||
case "Z":
|
||||
case "C":
|
||||
// Counter
|
||||
dataType = DataType.Counter;
|
||||
dbNumber = 0;
|
||||
address = int.Parse(input.Substring(1));
|
||||
varType = VarType.Counter;
|
||||
return;
|
||||
default:
|
||||
throw new InvalidAddressException(string.Format("{0} is not a valid address", input.Substring(0, 1)));
|
||||
}
|
||||
|
||||
string txt2 = input.Substring(1);
|
||||
if (txt2.IndexOf(".") == -1)
|
||||
throw new InvalidAddressException("To few periods for DB address");
|
||||
|
||||
address = int.Parse(txt2.Substring(0, txt2.IndexOf(".")));
|
||||
bitNumber = int.Parse(txt2.Substring(txt2.IndexOf(".") + 1));
|
||||
if (bitNumber > 7)
|
||||
throw new InvalidAddressException("Bit can only be 0-7");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
113
S7.Net/PLCExceptions.cs
Normal file
113
S7.Net/PLCExceptions.cs
Normal file
@@ -0,0 +1,113 @@
|
||||
using System;
|
||||
#if NET_FULL
|
||||
using System.Runtime.Serialization;
|
||||
#endif
|
||||
|
||||
|
||||
namespace S7.Net
|
||||
{
|
||||
internal class WrongNumberOfBytesException : Exception
|
||||
{
|
||||
public WrongNumberOfBytesException() : base()
|
||||
{
|
||||
}
|
||||
|
||||
public WrongNumberOfBytesException(string message) : base(message)
|
||||
{
|
||||
}
|
||||
|
||||
public WrongNumberOfBytesException(string message, Exception innerException) : base(message, innerException)
|
||||
{
|
||||
}
|
||||
|
||||
#if NET_FULL
|
||||
protected WrongNumberOfBytesException(SerializationInfo info, StreamingContext context) : base(info, context)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
internal class InvalidAddressException : Exception
|
||||
{
|
||||
public InvalidAddressException() : base ()
|
||||
{
|
||||
}
|
||||
|
||||
public InvalidAddressException(string message) : base(message)
|
||||
{
|
||||
}
|
||||
|
||||
public InvalidAddressException(string message, Exception innerException) : base(message, innerException)
|
||||
{
|
||||
}
|
||||
|
||||
#if NET_FULL
|
||||
protected InvalidAddressException(SerializationInfo info, StreamingContext context) : base(info, context)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
internal class InvalidVariableTypeException : Exception
|
||||
{
|
||||
public InvalidVariableTypeException() : base()
|
||||
{
|
||||
}
|
||||
|
||||
public InvalidVariableTypeException(string message) : base(message)
|
||||
{
|
||||
}
|
||||
|
||||
public InvalidVariableTypeException(string message, Exception innerException) : base(message, innerException)
|
||||
{
|
||||
}
|
||||
|
||||
#if NET_FULL
|
||||
protected InvalidVariableTypeException(SerializationInfo info, StreamingContext context) : base(info, context)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
internal class TPKTInvalidException : Exception
|
||||
{
|
||||
public TPKTInvalidException() : base()
|
||||
{
|
||||
}
|
||||
|
||||
public TPKTInvalidException(string message) : base(message)
|
||||
{
|
||||
}
|
||||
|
||||
public TPKTInvalidException(string message, Exception innerException) : base(message, innerException)
|
||||
{
|
||||
}
|
||||
|
||||
#if NET_FULL
|
||||
protected TPKTInvalidException(SerializationInfo info, StreamingContext context) : base(info, context)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
internal class TPDUInvalidException : Exception
|
||||
{
|
||||
public TPDUInvalidException() : base()
|
||||
{
|
||||
}
|
||||
|
||||
public TPDUInvalidException(string message) : base(message)
|
||||
{
|
||||
}
|
||||
|
||||
public TPDUInvalidException(string message, Exception innerException) : base(message, innerException)
|
||||
{
|
||||
}
|
||||
|
||||
#if NET_FULL
|
||||
protected TPDUInvalidException(SerializationInfo info, StreamingContext context) : base(info, context)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
266
S7.Net/PLCHelpers.cs
Normal file
266
S7.Net/PLCHelpers.cs
Normal file
@@ -0,0 +1,266 @@
|
||||
using S7.Net.Helper;
|
||||
using S7.Net.Protocol.S7;
|
||||
using S7.Net.Types;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using DateTime = S7.Net.Types.DateTime;
|
||||
|
||||
namespace S7.Net
|
||||
{
|
||||
public partial class Plc
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates the header to read bytes from the PLC
|
||||
/// </summary>
|
||||
/// <param name="amount"></param>
|
||||
/// <returns></returns>
|
||||
private static void BuildHeaderPackage(System.IO.MemoryStream stream, int amount = 1)
|
||||
{
|
||||
//header size = 19 bytes
|
||||
stream.WriteByteArray(new byte[] { 0x03, 0x00 });
|
||||
//complete package size
|
||||
stream.WriteByteArray(Types.Int.ToByteArray((short)(19 + (12 * amount))));
|
||||
stream.WriteByteArray(new byte[] { 0x02, 0xf0, 0x80, 0x32, 0x01, 0x00, 0x00, 0x00, 0x00 });
|
||||
//data part size
|
||||
stream.WriteByteArray(Types.Word.ToByteArray((ushort)(2 + (amount * 12))));
|
||||
stream.WriteByteArray(new byte[] { 0x00, 0x00, 0x04 });
|
||||
//amount of requests
|
||||
stream.WriteByte((byte)amount);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create the bytes-package to request data from the PLC. You have to specify the memory type (dataType),
|
||||
/// the address of the memory, the address of the byte and the bytes count.
|
||||
/// </summary>
|
||||
/// <param name="dataType">MemoryType (DB, Timer, Counter, etc.)</param>
|
||||
/// <param name="db">Address of the memory to be read</param>
|
||||
/// <param name="startByteAdr">Start address of the byte</param>
|
||||
/// <param name="count">Number of bytes to be read</param>
|
||||
/// <returns></returns>
|
||||
private static void BuildReadDataRequestPackage(System.IO.MemoryStream stream, DataType dataType, int db, int startByteAdr, int count = 1)
|
||||
{
|
||||
//single data req = 12
|
||||
stream.WriteByteArray(new byte[] { 0x12, 0x0a, 0x10 });
|
||||
switch (dataType)
|
||||
{
|
||||
case DataType.Timer:
|
||||
case DataType.Counter:
|
||||
stream.WriteByte((byte)dataType);
|
||||
break;
|
||||
default:
|
||||
stream.WriteByte(0x02);
|
||||
break;
|
||||
}
|
||||
|
||||
stream.WriteByteArray(Word.ToByteArray((ushort)(count)));
|
||||
stream.WriteByteArray(Word.ToByteArray((ushort)(db)));
|
||||
stream.WriteByte((byte)dataType);
|
||||
var overflow = (int)(startByteAdr * 8 / 0xffffU); // handles words with address bigger than 8191
|
||||
stream.WriteByte((byte)overflow);
|
||||
switch (dataType)
|
||||
{
|
||||
case DataType.Timer:
|
||||
case DataType.Counter:
|
||||
stream.WriteByteArray(Types.Word.ToByteArray((ushort)(startByteAdr)));
|
||||
break;
|
||||
default:
|
||||
stream.WriteByteArray(Types.Word.ToByteArray((ushort)((startByteAdr) * 8)));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Given a S7 variable type (Bool, Word, DWord, etc.), it converts the bytes in the appropriate C# format.
|
||||
/// </summary>
|
||||
/// <param name="varType"></param>
|
||||
/// <param name="bytes"></param>
|
||||
/// <param name="varCount"></param>
|
||||
/// <param name="bitAdr"></param>
|
||||
/// <returns></returns>
|
||||
private object? ParseBytes(VarType varType, byte[] bytes, int varCount, byte bitAdr = 0)
|
||||
{
|
||||
if (bytes == null || bytes.Length == 0)
|
||||
return null;
|
||||
|
||||
switch (varType)
|
||||
{
|
||||
case VarType.Byte:
|
||||
if (varCount == 1)
|
||||
return bytes[0];
|
||||
else
|
||||
return bytes;
|
||||
case VarType.Word:
|
||||
if (varCount == 1)
|
||||
return Word.FromByteArray(bytes);
|
||||
else
|
||||
return Word.ToArray(bytes);
|
||||
case VarType.Int:
|
||||
if (varCount == 1)
|
||||
return Int.FromByteArray(bytes);
|
||||
else
|
||||
return Int.ToArray(bytes);
|
||||
case VarType.DWord:
|
||||
if (varCount == 1)
|
||||
return DWord.FromByteArray(bytes);
|
||||
else
|
||||
return DWord.ToArray(bytes);
|
||||
case VarType.DInt:
|
||||
if (varCount == 1)
|
||||
return DInt.FromByteArray(bytes);
|
||||
else
|
||||
return DInt.ToArray(bytes);
|
||||
case VarType.Real:
|
||||
if (varCount == 1)
|
||||
return Types.Real.FromByteArray(bytes);
|
||||
else
|
||||
return Types.Real.ToArray(bytes);
|
||||
case VarType.LReal:
|
||||
if (varCount == 1)
|
||||
return Types.LReal.FromByteArray(bytes);
|
||||
else
|
||||
return Types.LReal.ToArray(bytes);
|
||||
|
||||
case VarType.String:
|
||||
return Types.String.FromByteArray(bytes);
|
||||
case VarType.S7String:
|
||||
return S7String.FromByteArray(bytes);
|
||||
case VarType.S7WString:
|
||||
return S7WString.FromByteArray(bytes);
|
||||
|
||||
case VarType.Timer:
|
||||
if (varCount == 1)
|
||||
return Timer.FromByteArray(bytes);
|
||||
else
|
||||
return Timer.ToArray(bytes);
|
||||
case VarType.Counter:
|
||||
if (varCount == 1)
|
||||
return Counter.FromByteArray(bytes);
|
||||
else
|
||||
return Counter.ToArray(bytes);
|
||||
case VarType.Bit:
|
||||
if (varCount == 1)
|
||||
{
|
||||
if (bitAdr > 7)
|
||||
return null;
|
||||
else
|
||||
return Bit.FromByte(bytes[0], bitAdr);
|
||||
}
|
||||
else
|
||||
{
|
||||
return Bit.ToBitArray(bytes, varCount);
|
||||
}
|
||||
case VarType.DateTime:
|
||||
if (varCount == 1)
|
||||
{
|
||||
return DateTime.FromByteArray(bytes);
|
||||
}
|
||||
else
|
||||
{
|
||||
return DateTime.ToArray(bytes);
|
||||
}
|
||||
case VarType.DateTimeLong:
|
||||
if (varCount == 1)
|
||||
{
|
||||
return DateTimeLong.FromByteArray(bytes);
|
||||
}
|
||||
else
|
||||
{
|
||||
return DateTimeLong.ToArray(bytes);
|
||||
}
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Given a S7 <see cref="VarType"/> (Bool, Word, DWord, etc.), it returns how many bytes to read.
|
||||
/// </summary>
|
||||
/// <param name="varType"></param>
|
||||
/// <param name="varCount"></param>
|
||||
/// <returns>Byte lenght of variable</returns>
|
||||
internal static int VarTypeToByteLength(VarType varType, int varCount = 1)
|
||||
{
|
||||
switch (varType)
|
||||
{
|
||||
case VarType.Bit:
|
||||
return varCount + 7 / 8;
|
||||
case VarType.Byte:
|
||||
return (varCount < 1) ? 1 : varCount;
|
||||
case VarType.String:
|
||||
return varCount;
|
||||
case VarType.S7String:
|
||||
return ((varCount + 2) & 1) == 1 ? (varCount + 3) : (varCount + 2);
|
||||
case VarType.S7WString:
|
||||
return (varCount * 2) + 4;
|
||||
case VarType.Word:
|
||||
case VarType.Timer:
|
||||
case VarType.Int:
|
||||
case VarType.Counter:
|
||||
return varCount * 2;
|
||||
case VarType.DWord:
|
||||
case VarType.DInt:
|
||||
case VarType.Real:
|
||||
return varCount * 4;
|
||||
case VarType.LReal:
|
||||
case VarType.DateTime:
|
||||
return varCount * 8;
|
||||
case VarType.DateTimeLong:
|
||||
return varCount * 12;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
private byte[] GetS7ConnectionSetup()
|
||||
{
|
||||
return new byte[] { 3, 0, 0, 25, 2, 240, 128, 50, 1, 0, 0, 255, 255, 0, 8, 0, 0, 240, 0, 0, 3, 0, 3,
|
||||
3, 192 // Use 960 PDU size
|
||||
};
|
||||
}
|
||||
|
||||
private void ParseDataIntoDataItems(byte[] s7data, List<DataItem> dataItems)
|
||||
{
|
||||
int offset = 14;
|
||||
foreach (var dataItem in dataItems)
|
||||
{
|
||||
// check for Return Code = Success
|
||||
if (s7data[offset] != 0xff)
|
||||
throw new PlcException(ErrorCode.WrongNumberReceivedBytes);
|
||||
|
||||
// to Data bytes
|
||||
offset += 4;
|
||||
|
||||
int byteCnt = VarTypeToByteLength(dataItem.VarType, dataItem.Count);
|
||||
dataItem.Value = ParseBytes(
|
||||
dataItem.VarType,
|
||||
s7data.Skip(offset).Take(byteCnt).ToArray(),
|
||||
dataItem.Count,
|
||||
dataItem.BitAdr
|
||||
);
|
||||
|
||||
// next Item
|
||||
offset += byteCnt;
|
||||
|
||||
// Fill byte in response when bytecount is odd
|
||||
if (dataItem.Count % 2 != 0 && (dataItem.VarType == VarType.Byte || dataItem.VarType == VarType.Bit))
|
||||
offset++;
|
||||
}
|
||||
}
|
||||
|
||||
private static byte[] BuildReadRequestPackage(IList<DataItemAddress> dataItems)
|
||||
{
|
||||
int packageSize = 19 + (dataItems.Count * 12);
|
||||
var package = new System.IO.MemoryStream(packageSize);
|
||||
|
||||
BuildHeaderPackage(package, dataItems.Count);
|
||||
|
||||
foreach (var dataItem in dataItems)
|
||||
{
|
||||
BuildReadDataRequestPackage(package, dataItem.DataType, dataItem.DB, dataItem.StartByteAddress, dataItem.ByteLength);
|
||||
}
|
||||
|
||||
return package.ToArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
532
S7.Net/PlcAsynchronous.cs
Normal file
532
S7.Net/PlcAsynchronous.cs
Normal file
@@ -0,0 +1,532 @@
|
||||
using S7.Net.Types;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net.Sockets;
|
||||
using System.Threading.Tasks;
|
||||
using S7.Net.Protocol;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using S7.Net.Protocol.S7;
|
||||
|
||||
namespace S7.Net
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates an instance of S7.Net driver
|
||||
/// </summary>
|
||||
public partial class Plc
|
||||
{
|
||||
/// <summary>
|
||||
/// Connects to the PLC and performs a COTP ConnectionRequest and S7 CommunicationSetup.
|
||||
/// </summary>
|
||||
/// <param name="cancellationToken">The token to monitor for cancellation requests. The default value is None.
|
||||
/// Please note that the cancellation will not affect opening the socket in any way and only affects data transfers for configuring the connection after the socket connection is successfully established.
|
||||
/// Please note that cancellation is advisory/cooperative and will not lead to immediate cancellation in all cases.</param>
|
||||
/// <returns>A task that represents the asynchronous open operation.</returns>
|
||||
public async Task OpenAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
var stream = await ConnectAsync().ConfigureAwait(false);
|
||||
try
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
await EstablishConnection(stream, cancellationToken).ConfigureAwait(false);
|
||||
_stream = stream;
|
||||
}
|
||||
catch(Exception)
|
||||
{
|
||||
stream.Dispose();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<NetworkStream> ConnectAsync()
|
||||
{
|
||||
tcpClient = new TcpClient();
|
||||
ConfigureConnection();
|
||||
await tcpClient.ConnectAsync(IP, Port).ConfigureAwait(false);
|
||||
return tcpClient.GetStream();
|
||||
}
|
||||
|
||||
private async Task EstablishConnection(NetworkStream stream, CancellationToken cancellationToken)
|
||||
{
|
||||
await RequestConnection(stream, cancellationToken).ConfigureAwait(false);
|
||||
await SetupConnection(stream, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private async Task RequestConnection(NetworkStream stream, CancellationToken cancellationToken)
|
||||
{
|
||||
var requestData = ConnectionRequest.GetCOTPConnectionRequest(CPU, Rack, Slot);
|
||||
await stream.WriteAsync(requestData, 0, requestData.Length).ConfigureAwait(false);
|
||||
var response = await COTP.TPDU.ReadAsync(stream, cancellationToken).ConfigureAwait(false);
|
||||
if (response.PDUType != COTP.PduType.ConnectionConfirmed)
|
||||
{
|
||||
throw new InvalidDataException("Connection request was denied", response.TPkt.Data, 1, 0x0d);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task SetupConnection(NetworkStream stream, CancellationToken cancellationToken)
|
||||
{
|
||||
var setupData = GetS7ConnectionSetup();
|
||||
await stream.WriteAsync(setupData, 0, setupData.Length).ConfigureAwait(false);
|
||||
|
||||
var s7data = await COTP.TSDU.ReadAsync(stream, cancellationToken).ConfigureAwait(false);
|
||||
if (s7data.Length < 2)
|
||||
throw new WrongNumberOfBytesException("Not enough data received in response to Communication Setup");
|
||||
|
||||
//Check for S7 Ack Data
|
||||
if (s7data[1] != 0x03)
|
||||
throw new InvalidDataException("Error reading Communication Setup response", s7data, 1, 0x03);
|
||||
|
||||
if (s7data.Length < 20)
|
||||
throw new WrongNumberOfBytesException("Not enough data received in response to Communication Setup");
|
||||
|
||||
// TODO: check if this should not rather be UInt16.
|
||||
MaxPDUSize = s7data[18] * 256 + s7data[19];
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Reads a number of bytes from a DB starting from a specified index. This handles more than 200 bytes with multiple requests.
|
||||
/// If the read was not successful, check LastErrorCode or LastErrorString.
|
||||
/// </summary>
|
||||
/// <param name="dataType">Data type of the memory area, can be DB, Timer, Counter, Merker(Memory), Input, Output.</param>
|
||||
/// <param name="db">Address of the memory area (if you want to read DB1, this is set to 1). This must be set also for other memory area types: counters, timers,etc.</param>
|
||||
/// <param name="startByteAdr">Start byte address. If you want to read DB1.DBW200, this is 200.</param>
|
||||
/// <param name="count">Byte count, if you want to read 120 bytes, set this to 120.</param>
|
||||
/// <param name="cancellationToken">The token to monitor for cancellation requests. The default value is None.
|
||||
/// Please note that cancellation is advisory/cooperative and will not lead to immediate cancellation in all cases.</param>
|
||||
/// <returns>Returns the bytes in an array</returns>
|
||||
public async Task<byte[]> ReadBytesAsync(DataType dataType, int db, int startByteAdr, int count, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var resultBytes = new byte[count];
|
||||
int index = 0;
|
||||
while (count > 0)
|
||||
{
|
||||
//This works up to MaxPDUSize-1 on SNAP7. But not MaxPDUSize-0.
|
||||
var maxToRead = Math.Min(count, MaxPDUSize - 18);
|
||||
await ReadBytesWithSingleRequestAsync(dataType, db, startByteAdr + index, resultBytes, index, maxToRead, cancellationToken).ConfigureAwait(false);
|
||||
count -= maxToRead;
|
||||
index += maxToRead;
|
||||
}
|
||||
return resultBytes;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read and decode a certain number of bytes of the "VarType" provided.
|
||||
/// This can be used to read multiple consecutive variables of the same type (Word, DWord, Int, etc).
|
||||
/// If the read was not successful, check LastErrorCode or LastErrorString.
|
||||
/// </summary>
|
||||
/// <param name="dataType">Data type of the memory area, can be DB, Timer, Counter, Merker(Memory), Input, Output.</param>
|
||||
/// <param name="db">Address of the memory area (if you want to read DB1, this is set to 1). This must be set also for other memory area types: counters, timers,etc.</param>
|
||||
/// <param name="startByteAdr">Start byte address. If you want to read DB1.DBW200, this is 200.</param>
|
||||
/// <param name="varType">Type of the variable/s that you are reading</param>
|
||||
/// <param name="bitAdr">Address of bit. If you want to read DB1.DBX200.6, set 6 to this parameter.</param>
|
||||
/// <param name="varCount"></param>
|
||||
/// <param name="cancellationToken">The token to monitor for cancellation requests. The default value is None.
|
||||
/// Please note that cancellation is advisory/cooperative and will not lead to immediate cancellation in all cases.</param>
|
||||
public async Task<object?> ReadAsync(DataType dataType, int db, int startByteAdr, VarType varType, int varCount, byte bitAdr = 0, CancellationToken cancellationToken = default)
|
||||
{
|
||||
int cntBytes = VarTypeToByteLength(varType, varCount);
|
||||
byte[] bytes = await ReadBytesAsync(dataType, db, startByteAdr, cntBytes, cancellationToken).ConfigureAwait(false);
|
||||
return ParseBytes(varType, bytes, varCount, bitAdr);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads a single variable from the PLC, takes in input strings like "DB1.DBX0.0", "DB20.DBD200", "MB20", "T45", etc.
|
||||
/// If the read was not successful, check LastErrorCode or LastErrorString.
|
||||
/// </summary>
|
||||
/// <param name="variable">Input strings like "DB1.DBX0.0", "DB20.DBD200", "MB20", "T45", etc.</param>
|
||||
/// <param name="cancellationToken">The token to monitor for cancellation requests. The default value is None.
|
||||
/// Please note that cancellation is advisory/cooperative and will not lead to immediate cancellation in all cases.</param>
|
||||
/// <returns>Returns an object that contains the value. This object must be cast accordingly.</returns>
|
||||
public async Task<object?> ReadAsync(string variable, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var adr = new PLCAddress(variable);
|
||||
return await ReadAsync(adr.DataType, adr.DbNumber, adr.StartByte, adr.VarType, 1, (byte)adr.BitNumber, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads all the bytes needed to fill a struct in C#, starting from a certain address, and return an object that can be casted to the struct.
|
||||
/// </summary>
|
||||
/// <param name="structType">Type of the struct to be readed (es.: TypeOf(MyStruct)).</param>
|
||||
/// <param name="db">Address of the DB.</param>
|
||||
/// <param name="startByteAdr">Start byte address. If you want to read DB1.DBW200, this is 200.</param>
|
||||
/// <param name="cancellationToken">The token to monitor for cancellation requests. The default value is None.
|
||||
/// Please note that cancellation is advisory/cooperative and will not lead to immediate cancellation in all cases.</param>
|
||||
/// <returns>Returns a struct that must be cast.</returns>
|
||||
public async Task<object?> ReadStructAsync(Type structType, int db, int startByteAdr = 0, CancellationToken cancellationToken = default)
|
||||
{
|
||||
int numBytes = Types.Struct.GetStructSize(structType);
|
||||
// now read the package
|
||||
var resultBytes = await ReadBytesAsync(DataType.DataBlock, db, startByteAdr, numBytes, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
// and decode it
|
||||
return Types.Struct.FromBytes(structType, resultBytes);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads all the bytes needed to fill a struct in C#, starting from a certain address, and returns the struct or null if nothing was read.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The struct type</typeparam>
|
||||
/// <param name="db">Address of the DB.</param>
|
||||
/// <param name="startByteAdr">Start byte address. If you want to read DB1.DBW200, this is 200.</param>
|
||||
/// <param name="cancellationToken">The token to monitor for cancellation requests. The default value is None.
|
||||
/// Please note that cancellation is advisory/cooperative and will not lead to immediate cancellation in all cases.</param>
|
||||
/// <returns>Returns a nulable struct. If nothing was read null will be returned.</returns>
|
||||
public async Task<T?> ReadStructAsync<T>(int db, int startByteAdr = 0, CancellationToken cancellationToken = default) where T : struct
|
||||
{
|
||||
return await ReadStructAsync(typeof(T), db, startByteAdr, cancellationToken).ConfigureAwait(false) as T?;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads all the bytes needed to fill a class in C#, starting from a certain address, and set all the properties values to the value that are read from the PLC.
|
||||
/// This reads only properties, it doesn't read private variable or public variable without {get;set;} specified.
|
||||
/// </summary>
|
||||
/// <param name="sourceClass">Instance of the class that will store the values</param>
|
||||
/// <param name="db">Index of the DB; es.: 1 is for DB1</param>
|
||||
/// <param name="startByteAdr">Start byte address. If you want to read DB1.DBW200, this is 200.</param>
|
||||
/// <param name="cancellationToken">The token to monitor for cancellation requests. The default value is None.
|
||||
/// Please note that cancellation is advisory/cooperative and will not lead to immediate cancellation in all cases.</param>
|
||||
/// <returns>The number of read bytes</returns>
|
||||
public async Task<Tuple<int, object>> ReadClassAsync(object sourceClass, int db, int startByteAdr = 0, CancellationToken cancellationToken = default)
|
||||
{
|
||||
int numBytes = (int)Class.GetClassSize(sourceClass);
|
||||
if (numBytes <= 0)
|
||||
{
|
||||
throw new Exception("The size of the class is less than 1 byte and therefore cannot be read");
|
||||
}
|
||||
|
||||
// now read the package
|
||||
var resultBytes = await ReadBytesAsync(DataType.DataBlock, db, startByteAdr, numBytes, cancellationToken).ConfigureAwait(false);
|
||||
// and decode it
|
||||
Class.FromBytes(sourceClass, resultBytes);
|
||||
|
||||
return new Tuple<int, object>(resultBytes.Length, sourceClass);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads all the bytes needed to fill a class in C#, starting from a certain address, and set all the properties values to the value that are read from the PLC.
|
||||
/// This reads only properties, it doesn't read private variable or public variable without {get;set;} specified. To instantiate the class defined by the generic
|
||||
/// type, the class needs a default constructor.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The class that will be instantiated. Requires a default constructor</typeparam>
|
||||
/// <param name="db">Index of the DB; es.: 1 is for DB1</param>
|
||||
/// <param name="startByteAdr">Start byte address. If you want to read DB1.DBW200, this is 200.</param>
|
||||
/// <param name="cancellationToken">The token to monitor for cancellation requests. The default value is None.
|
||||
/// Please note that cancellation is advisory/cooperative and will not lead to immediate cancellation in all cases.</param>
|
||||
/// <returns>An instance of the class with the values read from the PLC. If no data has been read, null will be returned</returns>
|
||||
public async Task<T?> ReadClassAsync<T>(int db, int startByteAdr = 0, CancellationToken cancellationToken = default) where T : class
|
||||
{
|
||||
return await ReadClassAsync(() => Activator.CreateInstance<T>(), db, startByteAdr, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads all the bytes needed to fill a class in C#, starting from a certain address, and set all the properties values to the value that are read from the PLC.
|
||||
/// This reads only properties, it doesn't read private variable or public variable without {get;set;} specified.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The class that will be instantiated</typeparam>
|
||||
/// <param name="classFactory">Function to instantiate the class</param>
|
||||
/// <param name="db">Index of the DB; es.: 1 is for DB1</param>
|
||||
/// <param name="startByteAdr">Start byte address. If you want to read DB1.DBW200, this is 200.</param>
|
||||
/// <param name="cancellationToken">The token to monitor for cancellation requests. The default value is None.
|
||||
/// Please note that cancellation is advisory/cooperative and will not lead to immediate cancellation in all cases.</param>
|
||||
/// <returns>An instance of the class with the values read from the PLC. If no data has been read, null will be returned</returns>
|
||||
public async Task<T?> ReadClassAsync<T>(Func<T> classFactory, int db, int startByteAdr = 0, CancellationToken cancellationToken = default) where T : class
|
||||
{
|
||||
var instance = classFactory();
|
||||
var res = await ReadClassAsync(instance, db, startByteAdr, cancellationToken).ConfigureAwait(false);
|
||||
int readBytes = res.Item1;
|
||||
if (readBytes <= 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return (T)res.Item2;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads multiple vars in a single request.
|
||||
/// You have to create and pass a list of DataItems and you obtain in response the same list with the values.
|
||||
/// Values are stored in the property "Value" of the dataItem and are already converted.
|
||||
/// If you don't want the conversion, just create a dataItem of bytes.
|
||||
/// The number of DataItems as well as the total size of the requested data can not exceed a certain limit (protocol restriction).
|
||||
/// </summary>
|
||||
/// <param name="dataItems">List of dataitems that contains the list of variables that must be read.</param>
|
||||
/// <param name="cancellationToken">The token to monitor for cancellation requests. The default value is None.
|
||||
/// Please note that cancellation is advisory/cooperative and will not lead to immediate cancellation in all cases.</param>
|
||||
public async Task<List<DataItem>> ReadMultipleVarsAsync(List<DataItem> dataItems, CancellationToken cancellationToken = default)
|
||||
{
|
||||
//Snap7 seems to choke on PDU sizes above 256 even if snap7
|
||||
//replies with bigger PDU size in connection setup.
|
||||
AssertPduSizeForRead(dataItems);
|
||||
|
||||
var stream = GetStreamIfAvailable();
|
||||
|
||||
try
|
||||
{
|
||||
var dataToSend = BuildReadRequestPackage(dataItems.Select(d => DataItem.GetDataItemAddress(d)).ToList());
|
||||
await stream.WriteAsync(dataToSend, 0, dataToSend.Length).ConfigureAwait(false);
|
||||
|
||||
var s7data = await COTP.TSDU.ReadAsync(stream, cancellationToken).ConfigureAwait(false);
|
||||
ValidateResponseCode((ReadWriteErrorCode)s7data[14]);
|
||||
|
||||
ParseDataIntoDataItems(s7data, dataItems);
|
||||
}
|
||||
catch (SocketException socketException)
|
||||
{
|
||||
throw new PlcException(ErrorCode.ReadData, socketException);
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
catch (Exception exc)
|
||||
{
|
||||
throw new PlcException(ErrorCode.ReadData, exc);
|
||||
}
|
||||
return dataItems;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Write a number of bytes from a DB starting from a specified index. This handles more than 200 bytes with multiple requests.
|
||||
/// If the write was not successful, check LastErrorCode or LastErrorString.
|
||||
/// </summary>
|
||||
/// <param name="dataType">Data type of the memory area, can be DB, Timer, Counter, Merker(Memory), Input, Output.</param>
|
||||
/// <param name="db">Address of the memory area (if you want to read DB1, this is set to 1). This must be set also for other memory area types: counters, timers,etc.</param>
|
||||
/// <param name="startByteAdr">Start byte address. If you want to write DB1.DBW200, this is 200.</param>
|
||||
/// <param name="value">Bytes to write. If more than 200, multiple requests will be made.</param>
|
||||
/// <param name="cancellationToken">The token to monitor for cancellation requests. The default value is None.
|
||||
/// Please note that cancellation is advisory/cooperative and will not lead to immediate cancellation in all cases.</param>
|
||||
/// <returns>A task that represents the asynchronous write operation.</returns>
|
||||
public async Task WriteBytesAsync(DataType dataType, int db, int startByteAdr, byte[] value, CancellationToken cancellationToken = default)
|
||||
{
|
||||
int localIndex = 0;
|
||||
int count = value.Length;
|
||||
while (count > 0)
|
||||
{
|
||||
var maxToWrite = (int)Math.Min(count, MaxPDUSize - 35);
|
||||
await WriteBytesWithASingleRequestAsync(dataType, db, startByteAdr + localIndex, value, localIndex, maxToWrite, cancellationToken).ConfigureAwait(false);
|
||||
count -= maxToWrite;
|
||||
localIndex += maxToWrite;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write a single bit from a DB with the specified index.
|
||||
/// </summary>
|
||||
/// <param name="dataType">Data type of the memory area, can be DB, Timer, Counter, Merker(Memory), Input, Output.</param>
|
||||
/// <param name="db">Address of the memory area (if you want to read DB1, this is set to 1). This must be set also for other memory area types: counters, timers,etc.</param>
|
||||
/// <param name="startByteAdr">Start byte address. If you want to write DB1.DBW200, this is 200.</param>
|
||||
/// <param name="bitAdr">The address of the bit. (0-7)</param>
|
||||
/// <param name="value">Bytes to write. If more than 200, multiple requests will be made.</param>
|
||||
/// <param name="cancellationToken">The token to monitor for cancellation requests. The default value is None.
|
||||
/// Please note that cancellation is advisory/cooperative and will not lead to immediate cancellation in all cases.</param>
|
||||
/// <returns>A task that represents the asynchronous write operation.</returns>
|
||||
public async Task WriteBitAsync(DataType dataType, int db, int startByteAdr, int bitAdr, bool value, CancellationToken cancellationToken = default)
|
||||
{
|
||||
if (bitAdr < 0 || bitAdr > 7)
|
||||
throw new InvalidAddressException(string.Format("Addressing Error: You can only reference bitwise locations 0-7. Address {0} is invalid", bitAdr));
|
||||
|
||||
await WriteBitWithASingleRequestAsync(dataType, db, startByteAdr, bitAdr, value, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write a single bit from a DB with the specified index.
|
||||
/// </summary>
|
||||
/// <param name="dataType">Data type of the memory area, can be DB, Timer, Counter, Merker(Memory), Input, Output.</param>
|
||||
/// <param name="db">Address of the memory area (if you want to read DB1, this is set to 1). This must be set also for other memory area types: counters, timers,etc.</param>
|
||||
/// <param name="startByteAdr">Start byte address. If you want to write DB1.DBW200, this is 200.</param>
|
||||
/// <param name="bitAdr">The address of the bit. (0-7)</param>
|
||||
/// <param name="value">Bytes to write. If more than 200, multiple requests will be made.</param>
|
||||
/// <param name="cancellationToken">The token to monitor for cancellation requests. The default value is None.
|
||||
/// Please note that cancellation is advisory/cooperative and will not lead to immediate cancellation in all cases.</param>
|
||||
/// <returns>A task that represents the asynchronous write operation.</returns>
|
||||
public async Task WriteBitAsync(DataType dataType, int db, int startByteAdr, int bitAdr, int value, CancellationToken cancellationToken = default)
|
||||
{
|
||||
if (value < 0 || value > 1)
|
||||
throw new ArgumentException("Value must be 0 or 1", nameof(value));
|
||||
|
||||
await WriteBitAsync(dataType, db, startByteAdr, bitAdr, value == 1, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Takes in input an object and tries to parse it to an array of values. This can be used to write many data, all of the same type.
|
||||
/// You must specify the memory area type, memory are address, byte start address and bytes count.
|
||||
/// If the read was not successful, check LastErrorCode or LastErrorString.
|
||||
/// </summary>
|
||||
/// <param name="dataType">Data type of the memory area, can be DB, Timer, Counter, Merker(Memory), Input, Output.</param>
|
||||
/// <param name="db">Address of the memory area (if you want to read DB1, this is set to 1). This must be set also for other memory area types: counters, timers,etc.</param>
|
||||
/// <param name="startByteAdr">Start byte address. If you want to read DB1.DBW200, this is 200.</param>
|
||||
/// <param name="value">Bytes to write. The lenght of this parameter can't be higher than 200. If you need more, use recursion.</param>
|
||||
/// <param name="bitAdr">The address of the bit. (0-7)</param>
|
||||
/// <param name="cancellationToken">The token to monitor for cancellation requests. The default value is None.
|
||||
/// Please note that cancellation is advisory/cooperative and will not lead to immediate cancellation in all cases.</param>
|
||||
/// <returns>A task that represents the asynchronous write operation.</returns>
|
||||
public async Task WriteAsync(DataType dataType, int db, int startByteAdr, object value, int bitAdr = -1, CancellationToken cancellationToken = default)
|
||||
{
|
||||
if (bitAdr != -1)
|
||||
{
|
||||
//Must be writing a bit value as bitAdr is specified
|
||||
if (value is bool boolean)
|
||||
{
|
||||
await WriteBitAsync(dataType, db, startByteAdr, bitAdr, boolean, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
else if (value is int intValue)
|
||||
{
|
||||
if (intValue < 0 || intValue > 7)
|
||||
throw new ArgumentOutOfRangeException(
|
||||
string.Format(
|
||||
"Addressing Error: You can only reference bitwise locations 0-7. Address {0} is invalid",
|
||||
bitAdr), nameof(bitAdr));
|
||||
|
||||
await WriteBitAsync(dataType, db, startByteAdr, bitAdr, intValue == 1, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
else throw new ArgumentException("Value must be a bool or an int to write a bit", nameof(value));
|
||||
}
|
||||
else await WriteBytesAsync(dataType, db, startByteAdr, Serialization.SerializeValue(value), cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a single variable from the PLC, takes in input strings like "DB1.DBX0.0", "DB20.DBD200", "MB20", "T45", etc.
|
||||
/// If the write was not successful, check <see cref="LastErrorCode"/> or <see cref="LastErrorString"/>.
|
||||
/// </summary>
|
||||
/// <param name="variable">Input strings like "DB1.DBX0.0", "DB20.DBD200", "MB20", "T45", etc.</param>
|
||||
/// <param name="value">Value to be written to the PLC</param>
|
||||
/// <param name="cancellationToken">The token to monitor for cancellation requests. The default value is None.
|
||||
/// Please note that cancellation is advisory/cooperative and will not lead to immediate cancellation in all cases.</param>
|
||||
/// <returns>A task that represents the asynchronous write operation.</returns>
|
||||
public async Task WriteAsync(string variable, object value, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var adr = new PLCAddress(variable);
|
||||
await WriteAsync(adr.DataType, adr.DbNumber, adr.StartByte, value, adr.BitNumber, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a C# struct to a DB in the PLC
|
||||
/// </summary>
|
||||
/// <param name="structValue">The struct to be written</param>
|
||||
/// <param name="db">Db address</param>
|
||||
/// <param name="startByteAdr">Start bytes on the PLC</param>
|
||||
/// <param name="cancellationToken">The token to monitor for cancellation requests. The default value is None.
|
||||
/// Please note that cancellation is advisory/cooperative and will not lead to immediate cancellation in all cases.</param>
|
||||
/// <returns>A task that represents the asynchronous write operation.</returns>
|
||||
public async Task WriteStructAsync(object structValue, int db, int startByteAdr = 0, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var bytes = Struct.ToBytes(structValue).ToList();
|
||||
await WriteBytesAsync(DataType.DataBlock, db, startByteAdr, bytes.ToArray(), cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a C# class to a DB in the PLC
|
||||
/// </summary>
|
||||
/// <param name="classValue">The class to be written</param>
|
||||
/// <param name="db">Db address</param>
|
||||
/// <param name="startByteAdr">Start bytes on the PLC</param>
|
||||
/// <param name="cancellationToken">The token to monitor for cancellation requests. The default value is None.
|
||||
/// Please note that cancellation is advisory/cooperative and will not lead to immediate cancellation in all cases.</param>
|
||||
/// <returns>A task that represents the asynchronous write operation.</returns>
|
||||
public async Task WriteClassAsync(object classValue, int db, int startByteAdr = 0, CancellationToken cancellationToken = default)
|
||||
{
|
||||
byte[] bytes = new byte[(int)Class.GetClassSize(classValue)];
|
||||
Types.Class.ToBytes(classValue, bytes);
|
||||
await WriteBytesAsync(DataType.DataBlock, db, startByteAdr, bytes, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private async Task ReadBytesWithSingleRequestAsync(DataType dataType, int db, int startByteAdr, byte[] buffer, int offset, int count, CancellationToken cancellationToken)
|
||||
{
|
||||
var stream = GetStreamIfAvailable();
|
||||
|
||||
var dataToSend = BuildReadRequestPackage(new [] { new DataItemAddress(dataType, db, startByteAdr, count)});
|
||||
await stream.WriteAsync(dataToSend, 0, dataToSend.Length, cancellationToken);
|
||||
|
||||
var s7data = await COTP.TSDU.ReadAsync(stream, cancellationToken).ConfigureAwait(false);
|
||||
AssertReadResponse(s7data, count);
|
||||
|
||||
Array.Copy(s7data, 18, buffer, offset, count);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write DataItem(s) to the PLC. Throws an exception if the response is invalid
|
||||
/// or when the PLC reports errors for item(s) written.
|
||||
/// </summary>
|
||||
/// <param name="dataItems">The DataItem(s) to write to the PLC.</param>
|
||||
/// <returns>Task that completes when response from PLC is parsed.</returns>
|
||||
public async Task WriteAsync(params DataItem[] dataItems)
|
||||
{
|
||||
AssertPduSizeForWrite(dataItems);
|
||||
|
||||
var stream = GetStreamIfAvailable();
|
||||
|
||||
var message = new ByteArray();
|
||||
var length = S7WriteMultiple.CreateRequest(message, dataItems);
|
||||
await stream.WriteAsync(message.Array, 0, length).ConfigureAwait(false);
|
||||
|
||||
var response = await COTP.TSDU.ReadAsync(stream, CancellationToken.None).ConfigureAwait(false);
|
||||
S7WriteMultiple.ParseResponse(response, response.Length, dataItems);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes up to 200 bytes to the PLC. You must specify the memory area type, memory are address, byte start address and bytes count.
|
||||
/// </summary>
|
||||
/// <param name="dataType">Data type of the memory area, can be DB, Timer, Counter, Merker(Memory), Input, Output.</param>
|
||||
/// <param name="db">Address of the memory area (if you want to read DB1, this is set to 1). This must be set also for other memory area types: counters, timers,etc.</param>
|
||||
/// <param name="startByteAdr">Start byte address. If you want to read DB1.DBW200, this is 200.</param>
|
||||
/// <param name="value">Bytes to write. The lenght of this parameter can't be higher than 200. If you need more, use recursion.</param>
|
||||
/// <returns>A task that represents the asynchronous write operation.</returns>
|
||||
private async Task WriteBytesWithASingleRequestAsync(DataType dataType, int db, int startByteAdr, byte[] value, int dataOffset, int count, CancellationToken cancellationToken)
|
||||
{
|
||||
|
||||
try
|
||||
{
|
||||
var stream = GetStreamIfAvailable();
|
||||
var dataToSend = BuildWriteBytesPackage(dataType, db, startByteAdr, value, dataOffset, count);
|
||||
|
||||
await stream.WriteAsync(dataToSend, 0, dataToSend.Length, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
var s7data = await COTP.TSDU.ReadAsync(stream, cancellationToken).ConfigureAwait(false);
|
||||
ValidateResponseCode((ReadWriteErrorCode)s7data[14]);
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
catch (Exception exc)
|
||||
{
|
||||
throw new PlcException(ErrorCode.WriteData, exc);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task WriteBitWithASingleRequestAsync(DataType dataType, int db, int startByteAdr, int bitAdr, bool bitValue, CancellationToken cancellationToken)
|
||||
{
|
||||
var stream = GetStreamIfAvailable();
|
||||
|
||||
try
|
||||
{
|
||||
var dataToSend = BuildWriteBitPackage(dataType, db, startByteAdr, bitValue, bitAdr);
|
||||
|
||||
await stream.WriteAsync(dataToSend, 0, dataToSend.Length).ConfigureAwait(false);
|
||||
|
||||
var s7data = await COTP.TSDU.ReadAsync(stream, cancellationToken).ConfigureAwait(false);
|
||||
ValidateResponseCode((ReadWriteErrorCode)s7data[14]);
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
catch (Exception exc)
|
||||
{
|
||||
throw new PlcException(ErrorCode.WriteData, exc);
|
||||
}
|
||||
}
|
||||
|
||||
private Stream GetStreamIfAvailable()
|
||||
{
|
||||
if (_stream == null)
|
||||
{
|
||||
throw new PlcException(ErrorCode.ConnectionError, "Plc is not connected");
|
||||
}
|
||||
return _stream;
|
||||
}
|
||||
}
|
||||
}
|
||||
39
S7.Net/PlcException.cs
Normal file
39
S7.Net/PlcException.cs
Normal file
@@ -0,0 +1,39 @@
|
||||
using System;
|
||||
|
||||
namespace S7.Net
|
||||
{
|
||||
#if NET_FULL
|
||||
[Serializable]
|
||||
#endif
|
||||
public class PlcException : Exception
|
||||
{
|
||||
public ErrorCode ErrorCode { get; }
|
||||
|
||||
public PlcException(ErrorCode errorCode) : this(errorCode, $"PLC communication failed with error '{errorCode}'.")
|
||||
{
|
||||
}
|
||||
|
||||
public PlcException(ErrorCode errorCode, Exception innerException) : this(errorCode, innerException.Message,
|
||||
innerException)
|
||||
{
|
||||
}
|
||||
|
||||
public PlcException(ErrorCode errorCode, string message) : base(message)
|
||||
{
|
||||
ErrorCode = errorCode;
|
||||
}
|
||||
|
||||
public PlcException(ErrorCode errorCode, string message, Exception inner) : base(message, inner)
|
||||
{
|
||||
ErrorCode = errorCode;
|
||||
}
|
||||
|
||||
#if NET_FULL
|
||||
protected PlcException(System.Runtime.Serialization.SerializationInfo info,
|
||||
System.Runtime.Serialization.StreamingContext context) : base(info, context)
|
||||
{
|
||||
ErrorCode = (ErrorCode) info.GetInt32(nameof(ErrorCode));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
485
S7.Net/PlcSynchronous.cs
Normal file
485
S7.Net/PlcSynchronous.cs
Normal file
@@ -0,0 +1,485 @@
|
||||
using S7.Net.Types;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net.Sockets;
|
||||
using S7.Net.Protocol;
|
||||
using S7.Net.Helper;
|
||||
|
||||
//Implement synchronous methods here
|
||||
namespace S7.Net
|
||||
{
|
||||
public partial class Plc
|
||||
{
|
||||
/// <summary>
|
||||
/// Connects to the PLC and performs a COTP ConnectionRequest and S7 CommunicationSetup.
|
||||
/// </summary>
|
||||
public void Open()
|
||||
{
|
||||
try
|
||||
{
|
||||
OpenAsync().GetAwaiter().GetResult();
|
||||
}
|
||||
catch (Exception exc)
|
||||
{
|
||||
throw new PlcException(ErrorCode.ConnectionError,
|
||||
$"Couldn't establish the connection to {IP}.\nMessage: {exc.Message}", exc);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Reads a number of bytes from a DB starting from a specified index. This handles more than 200 bytes with multiple requests.
|
||||
/// If the read was not successful, check LastErrorCode or LastErrorString.
|
||||
/// </summary>
|
||||
/// <param name="dataType">Data type of the memory area, can be DB, Timer, Counter, Merker(Memory), Input, Output.</param>
|
||||
/// <param name="db">Address of the memory area (if you want to read DB1, this is set to 1). This must be set also for other memory area types: counters, timers,etc.</param>
|
||||
/// <param name="startByteAdr">Start byte address. If you want to read DB1.DBW200, this is 200.</param>
|
||||
/// <param name="count">Byte count, if you want to read 120 bytes, set this to 120.</param>
|
||||
/// <returns>Returns the bytes in an array</returns>
|
||||
public byte[] ReadBytes(DataType dataType, int db, int startByteAdr, int count)
|
||||
{
|
||||
var result = new byte[count];
|
||||
int index = 0;
|
||||
while (count > 0)
|
||||
{
|
||||
//This works up to MaxPDUSize-1 on SNAP7. But not MaxPDUSize-0.
|
||||
var maxToRead = Math.Min(count, MaxPDUSize - 18);
|
||||
ReadBytesWithSingleRequest(dataType, db, startByteAdr + index, result, index, maxToRead);
|
||||
count -= maxToRead;
|
||||
index += maxToRead;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read and decode a certain number of bytes of the "VarType" provided.
|
||||
/// This can be used to read multiple consecutive variables of the same type (Word, DWord, Int, etc).
|
||||
/// If the read was not successful, check LastErrorCode or LastErrorString.
|
||||
/// </summary>
|
||||
/// <param name="dataType">Data type of the memory area, can be DB, Timer, Counter, Merker(Memory), Input, Output.</param>
|
||||
/// <param name="db">Address of the memory area (if you want to read DB1, this is set to 1). This must be set also for other memory area types: counters, timers,etc.</param>
|
||||
/// <param name="startByteAdr">Start byte address. If you want to read DB1.DBW200, this is 200.</param>
|
||||
/// <param name="varType">Type of the variable/s that you are reading</param>
|
||||
/// <param name="bitAdr">Address of bit. If you want to read DB1.DBX200.6, set 6 to this parameter.</param>
|
||||
/// <param name="varCount"></param>
|
||||
public object? Read(DataType dataType, int db, int startByteAdr, VarType varType, int varCount, byte bitAdr = 0)
|
||||
{
|
||||
int cntBytes = VarTypeToByteLength(varType, varCount);
|
||||
byte[] bytes = ReadBytes(dataType, db, startByteAdr, cntBytes);
|
||||
|
||||
return ParseBytes(varType, bytes, varCount, bitAdr);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads a single variable from the PLC, takes in input strings like "DB1.DBX0.0", "DB20.DBD200", "MB20", "T45", etc.
|
||||
/// If the read was not successful, check LastErrorCode or LastErrorString.
|
||||
/// </summary>
|
||||
/// <param name="variable">Input strings like "DB1.DBX0.0", "DB20.DBD200", "MB20", "T45", etc.</param>
|
||||
/// <returns>Returns an object that contains the value. This object must be cast accordingly. If no data has been read, null will be returned</returns>
|
||||
public object? Read(string variable)
|
||||
{
|
||||
var adr = new PLCAddress(variable);
|
||||
return Read(adr.DataType, adr.DbNumber, adr.StartByte, adr.VarType, 1, (byte)adr.BitNumber);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads all the bytes needed to fill a struct in C#, starting from a certain address, and return an object that can be casted to the struct.
|
||||
/// </summary>
|
||||
/// <param name="structType">Type of the struct to be readed (es.: TypeOf(MyStruct)).</param>
|
||||
/// <param name="db">Address of the DB.</param>
|
||||
/// <param name="startByteAdr">Start byte address. If you want to read DB1.DBW200, this is 200.</param>
|
||||
/// <returns>Returns a struct that must be cast. If no data has been read, null will be returned</returns>
|
||||
public object? ReadStruct(Type structType, int db, int startByteAdr = 0)
|
||||
{
|
||||
int numBytes = Struct.GetStructSize(structType);
|
||||
// now read the package
|
||||
var resultBytes = ReadBytes(DataType.DataBlock, db, startByteAdr, numBytes);
|
||||
|
||||
// and decode it
|
||||
return Struct.FromBytes(structType, resultBytes);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads all the bytes needed to fill a struct in C#, starting from a certain address, and returns the struct or null if nothing was read.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The struct type</typeparam>
|
||||
/// <param name="db">Address of the DB.</param>
|
||||
/// <param name="startByteAdr">Start byte address. If you want to read DB1.DBW200, this is 200.</param>
|
||||
/// <returns>Returns a nullable struct. If nothing was read null will be returned.</returns>
|
||||
public T? ReadStruct<T>(int db, int startByteAdr = 0) where T : struct
|
||||
{
|
||||
return ReadStruct(typeof(T), db, startByteAdr) as T?;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Reads all the bytes needed to fill a class in C#, starting from a certain address, and set all the properties values to the value that are read from the PLC.
|
||||
/// This reads only properties, it doesn't read private variable or public variable without {get;set;} specified.
|
||||
/// </summary>
|
||||
/// <param name="sourceClass">Instance of the class that will store the values</param>
|
||||
/// <param name="db">Index of the DB; es.: 1 is for DB1</param>
|
||||
/// <param name="startByteAdr">Start byte address. If you want to read DB1.DBW200, this is 200.</param>
|
||||
/// <returns>The number of read bytes</returns>
|
||||
public int ReadClass(object sourceClass, int db, int startByteAdr = 0)
|
||||
{
|
||||
int numBytes = (int)Class.GetClassSize(sourceClass);
|
||||
if (numBytes <= 0)
|
||||
{
|
||||
throw new Exception("The size of the class is less than 1 byte and therefore cannot be read");
|
||||
}
|
||||
|
||||
// now read the package
|
||||
var resultBytes = ReadBytes(DataType.DataBlock, db, startByteAdr, numBytes);
|
||||
// and decode it
|
||||
Class.FromBytes(sourceClass, resultBytes);
|
||||
return resultBytes.Length;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads all the bytes needed to fill a class in C#, starting from a certain address, and set all the properties values to the value that are read from the PLC.
|
||||
/// This reads only properties, it doesn't read private variable or public variable without {get;set;} specified. To instantiate the class defined by the generic
|
||||
/// type, the class needs a default constructor.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The class that will be instantiated. Requires a default constructor</typeparam>
|
||||
/// <param name="db">Index of the DB; es.: 1 is for DB1</param>
|
||||
/// <param name="startByteAdr">Start byte address. If you want to read DB1.DBW200, this is 200.</param>
|
||||
/// <returns>An instance of the class with the values read from the PLC. If no data has been read, null will be returned</returns>
|
||||
public T? ReadClass<T>(int db, int startByteAdr = 0) where T : class
|
||||
{
|
||||
return ReadClass(() => Activator.CreateInstance<T>(), db, startByteAdr);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads all the bytes needed to fill a class in C#, starting from a certain address, and set all the properties values to the value that are read from the PLC.
|
||||
/// This reads only properties, it doesn't read private variable or public variable without {get;set;} specified.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The class that will be instantiated</typeparam>
|
||||
/// <param name="classFactory">Function to instantiate the class</param>
|
||||
/// <param name="db">Index of the DB; es.: 1 is for DB1</param>
|
||||
/// <param name="startByteAdr">Start byte address. If you want to read DB1.DBW200, this is 200.</param>
|
||||
/// <returns>An instance of the class with the values read from the PLC. If no data has been read, null will be returned</returns>
|
||||
public T? ReadClass<T>(Func<T> classFactory, int db, int startByteAdr = 0) where T : class
|
||||
{
|
||||
var instance = classFactory();
|
||||
int readBytes = ReadClass(instance, db, startByteAdr);
|
||||
if (readBytes <= 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write a number of bytes from a DB starting from a specified index. This handles more than 200 bytes with multiple requests.
|
||||
/// If the write was not successful, check LastErrorCode or LastErrorString.
|
||||
/// </summary>
|
||||
/// <param name="dataType">Data type of the memory area, can be DB, Timer, Counter, Merker(Memory), Input, Output.</param>
|
||||
/// <param name="db">Address of the memory area (if you want to read DB1, this is set to 1). This must be set also for other memory area types: counters, timers,etc.</param>
|
||||
/// <param name="startByteAdr">Start byte address. If you want to write DB1.DBW200, this is 200.</param>
|
||||
/// <param name="value">Bytes to write. If more than 200, multiple requests will be made.</param>
|
||||
public void WriteBytes(DataType dataType, int db, int startByteAdr, byte[] value)
|
||||
{
|
||||
int localIndex = 0;
|
||||
int count = value.Length;
|
||||
while (count > 0)
|
||||
{
|
||||
//TODO: Figure out how to use MaxPDUSize here
|
||||
//Snap7 seems to choke on PDU sizes above 256 even if snap7
|
||||
//replies with bigger PDU size in connection setup.
|
||||
var maxToWrite = Math.Min(count, MaxPDUSize - 28);//TODO tested only when the MaxPDUSize is 480
|
||||
WriteBytesWithASingleRequest(dataType, db, startByteAdr + localIndex, value, localIndex, maxToWrite);
|
||||
count -= maxToWrite;
|
||||
localIndex += maxToWrite;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write a single bit from a DB with the specified index.
|
||||
/// </summary>
|
||||
/// <param name="dataType">Data type of the memory area, can be DB, Timer, Counter, Merker(Memory), Input, Output.</param>
|
||||
/// <param name="db">Address of the memory area (if you want to read DB1, this is set to 1). This must be set also for other memory area types: counters, timers,etc.</param>
|
||||
/// <param name="startByteAdr">Start byte address. If you want to write DB1.DBW200, this is 200.</param>
|
||||
/// <param name="bitAdr">The address of the bit. (0-7)</param>
|
||||
/// <param name="value">Bytes to write. If more than 200, multiple requests will be made.</param>
|
||||
public void WriteBit(DataType dataType, int db, int startByteAdr, int bitAdr, bool value)
|
||||
{
|
||||
if (bitAdr < 0 || bitAdr > 7)
|
||||
throw new InvalidAddressException(string.Format("Addressing Error: You can only reference bitwise locations 0-7. Address {0} is invalid", bitAdr));
|
||||
|
||||
WriteBitWithASingleRequest(dataType, db, startByteAdr, bitAdr, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write a single bit to a DB with the specified index.
|
||||
/// </summary>
|
||||
/// <param name="dataType">Data type of the memory area, can be DB, Timer, Counter, Merker(Memory), Input, Output.</param>
|
||||
/// <param name="db">Address of the memory area (if you want to write DB1, this is set to 1). This must be set also for other memory area types: counters, timers,etc.</param>
|
||||
/// <param name="startByteAdr">Start byte address. If you want to write DB1.DBW200, this is 200.</param>
|
||||
/// <param name="bitAdr">The address of the bit. (0-7)</param>
|
||||
/// <param name="value">Value to write (0 or 1).</param>
|
||||
public void WriteBit(DataType dataType, int db, int startByteAdr, int bitAdr, int value)
|
||||
{
|
||||
if (value < 0 || value > 1)
|
||||
throw new ArgumentException("Value must be 0 or 1", nameof(value));
|
||||
|
||||
WriteBit(dataType, db, startByteAdr, bitAdr, value == 1);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Takes in input an object and tries to parse it to an array of values. This can be used to write many data, all of the same type.
|
||||
/// You must specify the memory area type, memory are address, byte start address and bytes count.
|
||||
/// If the read was not successful, check LastErrorCode or LastErrorString.
|
||||
/// </summary>
|
||||
/// <param name="dataType">Data type of the memory area, can be DB, Timer, Counter, Merker(Memory), Input, Output.</param>
|
||||
/// <param name="db">Address of the memory area (if you want to read DB1, this is set to 1). This must be set also for other memory area types: counters, timers,etc.</param>
|
||||
/// <param name="startByteAdr">Start byte address. If you want to read DB1.DBW200, this is 200.</param>
|
||||
/// <param name="value">Bytes to write. The lenght of this parameter can't be higher than 200. If you need more, use recursion.</param>
|
||||
/// <param name="bitAdr">The address of the bit. (0-7)</param>
|
||||
public void Write(DataType dataType, int db, int startByteAdr, object value, int bitAdr = -1)
|
||||
{
|
||||
if (bitAdr != -1)
|
||||
{
|
||||
//Must be writing a bit value as bitAdr is specified
|
||||
if (value is bool boolean)
|
||||
{
|
||||
WriteBit(dataType, db, startByteAdr, bitAdr, boolean);
|
||||
}
|
||||
else if (value is int intValue)
|
||||
{
|
||||
if (intValue < 0 || intValue > 7)
|
||||
throw new ArgumentOutOfRangeException(
|
||||
string.Format(
|
||||
"Addressing Error: You can only reference bitwise locations 0-7. Address {0} is invalid",
|
||||
bitAdr), nameof(bitAdr));
|
||||
|
||||
WriteBit(dataType, db, startByteAdr, bitAdr, intValue == 1);
|
||||
}
|
||||
else
|
||||
throw new ArgumentException("Value must be a bool or an int to write a bit", nameof(value));
|
||||
}
|
||||
else WriteBytes(dataType, db, startByteAdr, Serialization.SerializeValue(value));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a single variable from the PLC, takes in input strings like "DB1.DBX0.0", "DB20.DBD200", "MB20", "T45", etc.
|
||||
/// If the write was not successful, check <see cref="LastErrorCode"/> or <see cref="LastErrorString"/>.
|
||||
/// </summary>
|
||||
/// <param name="variable">Input strings like "DB1.DBX0.0", "DB20.DBD200", "MB20", "T45", etc.</param>
|
||||
/// <param name="value">Value to be written to the PLC</param>
|
||||
public void Write(string variable, object value)
|
||||
{
|
||||
var adr = new PLCAddress(variable);
|
||||
Write(adr.DataType, adr.DbNumber, adr.StartByte, value, adr.BitNumber);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a C# struct to a DB in the PLC
|
||||
/// </summary>
|
||||
/// <param name="structValue">The struct to be written</param>
|
||||
/// <param name="db">Db address</param>
|
||||
/// <param name="startByteAdr">Start bytes on the PLC</param>
|
||||
public void WriteStruct(object structValue, int db, int startByteAdr = 0)
|
||||
{
|
||||
WriteStructAsync(structValue, db, startByteAdr).GetAwaiter().GetResult();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a C# class to a DB in the PLC
|
||||
/// </summary>
|
||||
/// <param name="classValue">The class to be written</param>
|
||||
/// <param name="db">Db address</param>
|
||||
/// <param name="startByteAdr">Start bytes on the PLC</param>
|
||||
public void WriteClass(object classValue, int db, int startByteAdr = 0)
|
||||
{
|
||||
WriteClassAsync(classValue, db, startByteAdr).GetAwaiter().GetResult();
|
||||
}
|
||||
|
||||
private void ReadBytesWithSingleRequest(DataType dataType, int db, int startByteAdr, byte[] buffer, int offset, int count)
|
||||
{
|
||||
var stream = GetStreamIfAvailable();
|
||||
try
|
||||
{
|
||||
// first create the header
|
||||
int packageSize = 19 + 12; // 19 header + 12 for 1 request
|
||||
var package = new System.IO.MemoryStream(packageSize);
|
||||
BuildHeaderPackage(package);
|
||||
// package.Add(0x02); // datenart
|
||||
BuildReadDataRequestPackage(package, dataType, db, startByteAdr, count);
|
||||
|
||||
var dataToSend = package.ToArray();
|
||||
stream.Write(dataToSend, 0, dataToSend.Length);
|
||||
|
||||
var s7data = COTP.TSDU.Read(stream);
|
||||
AssertReadResponse(s7data, count);
|
||||
|
||||
Array.Copy(s7data, 18, buffer, offset, count);
|
||||
}
|
||||
catch (Exception exc)
|
||||
{
|
||||
throw new PlcException(ErrorCode.ReadData, exc);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write DataItem(s) to the PLC. Throws an exception if the response is invalid
|
||||
/// or when the PLC reports errors for item(s) written.
|
||||
/// </summary>
|
||||
/// <param name="dataItems">The DataItem(s) to write to the PLC.</param>
|
||||
public void Write(params DataItem[] dataItems)
|
||||
{
|
||||
AssertPduSizeForWrite(dataItems);
|
||||
|
||||
var stream = GetStreamIfAvailable();
|
||||
|
||||
var message = new ByteArray();
|
||||
var length = S7WriteMultiple.CreateRequest(message, dataItems);
|
||||
stream.Write(message.Array, 0, length);
|
||||
|
||||
var response = COTP.TSDU.Read(stream);
|
||||
S7WriteMultiple.ParseResponse(response, response.Length, dataItems);
|
||||
}
|
||||
|
||||
private void WriteBytesWithASingleRequest(DataType dataType, int db, int startByteAdr, byte[] value, int dataOffset, int count)
|
||||
{
|
||||
try
|
||||
{
|
||||
var stream = GetStreamIfAvailable();
|
||||
var dataToSend = BuildWriteBytesPackage(dataType, db, startByteAdr, value, dataOffset, count);
|
||||
|
||||
stream.Write(dataToSend, 0, dataToSend.Length);
|
||||
|
||||
var s7data = COTP.TSDU.Read(stream);
|
||||
ValidateResponseCode((ReadWriteErrorCode)s7data[14]);
|
||||
}
|
||||
catch (Exception exc)
|
||||
{
|
||||
throw new PlcException(ErrorCode.WriteData, exc);
|
||||
}
|
||||
}
|
||||
|
||||
private byte[] BuildWriteBytesPackage(DataType dataType, int db, int startByteAdr, byte[] value, int dataOffset, int count)
|
||||
{
|
||||
int varCount = count;
|
||||
// first create the header
|
||||
int packageSize = 35 + varCount;
|
||||
var package = new MemoryStream(new byte[packageSize]);
|
||||
|
||||
package.WriteByte(3);
|
||||
package.WriteByte(0);
|
||||
//complete package size
|
||||
package.WriteByteArray(Int.ToByteArray((short)packageSize));
|
||||
package.WriteByteArray(new byte[] { 2, 0xf0, 0x80, 0x32, 1, 0, 0 });
|
||||
package.WriteByteArray(Word.ToByteArray((ushort)(varCount - 1)));
|
||||
package.WriteByteArray(new byte[] { 0, 0x0e });
|
||||
package.WriteByteArray(Word.ToByteArray((ushort)(varCount + 4)));
|
||||
package.WriteByteArray(new byte[] { 0x05, 0x01, 0x12, 0x0a, 0x10, 0x02 });
|
||||
package.WriteByteArray(Word.ToByteArray((ushort)varCount));
|
||||
package.WriteByteArray(Word.ToByteArray((ushort)(db)));
|
||||
package.WriteByte((byte)dataType);
|
||||
var overflow = (int)(startByteAdr * 8 / 0xffffU); // handles words with address bigger than 8191
|
||||
package.WriteByte((byte)overflow);
|
||||
package.WriteByteArray(Word.ToByteArray((ushort)(startByteAdr * 8)));
|
||||
package.WriteByteArray(new byte[] { 0, 4 });
|
||||
package.WriteByteArray(Word.ToByteArray((ushort)(varCount * 8)));
|
||||
|
||||
// now join the header and the data
|
||||
package.Write(value, dataOffset, count);
|
||||
|
||||
return package.ToArray();
|
||||
}
|
||||
|
||||
private byte[] BuildWriteBitPackage(DataType dataType, int db, int startByteAdr, bool bitValue, int bitAdr)
|
||||
{
|
||||
var value = new[] { bitValue ? (byte)1 : (byte)0 };
|
||||
int varCount = 1;
|
||||
// first create the header
|
||||
int packageSize = 35 + varCount;
|
||||
var package = new MemoryStream(new byte[packageSize]);
|
||||
|
||||
package.WriteByte(3);
|
||||
package.WriteByte(0);
|
||||
//complete package size
|
||||
package.WriteByteArray(Int.ToByteArray((short)packageSize));
|
||||
package.WriteByteArray(new byte[] { 2, 0xf0, 0x80, 0x32, 1, 0, 0 });
|
||||
package.WriteByteArray(Word.ToByteArray((ushort)(varCount - 1)));
|
||||
package.WriteByteArray(new byte[] { 0, 0x0e });
|
||||
package.WriteByteArray(Word.ToByteArray((ushort)(varCount + 4)));
|
||||
package.WriteByteArray(new byte[] { 0x05, 0x01, 0x12, 0x0a, 0x10, 0x01 }); //ending 0x01 is used for writing a sinlge bit
|
||||
package.WriteByteArray(Word.ToByteArray((ushort)varCount));
|
||||
package.WriteByteArray(Word.ToByteArray((ushort)(db)));
|
||||
package.WriteByte((byte)dataType);
|
||||
var overflow = (int)(startByteAdr * 8 / 0xffffU); // handles words with address bigger than 8191
|
||||
package.WriteByte((byte)overflow);
|
||||
package.WriteByteArray(Word.ToByteArray((ushort)(startByteAdr * 8 + bitAdr)));
|
||||
package.WriteByteArray(new byte[] { 0, 0x03 }); //ending 0x03 is used for writing a sinlge bit
|
||||
package.WriteByteArray(Word.ToByteArray((ushort)(varCount)));
|
||||
|
||||
// now join the header and the data
|
||||
package.WriteByteArray(value);
|
||||
|
||||
return package.ToArray();
|
||||
}
|
||||
|
||||
|
||||
private void WriteBitWithASingleRequest(DataType dataType, int db, int startByteAdr, int bitAdr, bool bitValue)
|
||||
{
|
||||
var stream = GetStreamIfAvailable();
|
||||
try
|
||||
{
|
||||
var dataToSend = BuildWriteBitPackage(dataType, db, startByteAdr, bitValue, bitAdr);
|
||||
|
||||
stream.Write(dataToSend, 0, dataToSend.Length);
|
||||
|
||||
var s7data = COTP.TSDU.Read(stream);
|
||||
ValidateResponseCode((ReadWriteErrorCode)s7data[14]);
|
||||
}
|
||||
catch (Exception exc)
|
||||
{
|
||||
throw new PlcException(ErrorCode.WriteData, exc);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads multiple vars in a single request.
|
||||
/// You have to create and pass a list of DataItems and you obtain in response the same list with the values.
|
||||
/// Values are stored in the property "Value" of the dataItem and are already converted.
|
||||
/// If you don't want the conversion, just create a dataItem of bytes.
|
||||
/// The number of DataItems as well as the total size of the requested data can not exceed a certain limit (protocol restriction).
|
||||
/// </summary>
|
||||
/// <param name="dataItems">List of dataitems that contains the list of variables that must be read.</param>
|
||||
public void ReadMultipleVars(List<DataItem> dataItems)
|
||||
{
|
||||
AssertPduSizeForRead(dataItems);
|
||||
|
||||
var stream = GetStreamIfAvailable();
|
||||
|
||||
try
|
||||
{
|
||||
// first create the header
|
||||
int packageSize = 19 + (dataItems.Count * 12);
|
||||
var package = new System.IO.MemoryStream(packageSize);
|
||||
BuildHeaderPackage(package, dataItems.Count);
|
||||
// package.Add(0x02); // datenart
|
||||
foreach (var dataItem in dataItems)
|
||||
{
|
||||
BuildReadDataRequestPackage(package, dataItem.DataType, dataItem.DB, dataItem.StartByteAdr, VarTypeToByteLength(dataItem.VarType, dataItem.Count));
|
||||
}
|
||||
|
||||
var dataToSend = package.ToArray();
|
||||
stream.Write(dataToSend, 0, dataToSend.Length);
|
||||
|
||||
var s7data = COTP.TSDU.Read(stream); //TODO use Async
|
||||
|
||||
ValidateResponseCode((ReadWriteErrorCode)s7data[14]);
|
||||
|
||||
ParseDataIntoDataItems(s7data, dataItems);
|
||||
}
|
||||
catch (Exception exc)
|
||||
{
|
||||
throw new PlcException(ErrorCode.ReadData, exc);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,36 +1,3 @@
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
// Allgemeine Informationen über eine Assembly werden über die folgenden
|
||||
// Attribute gesteuert. Ändern Sie diese Attributwerte, um die Informationen zu ändern,
|
||||
// die mit einer Assembly verknüpft sind.
|
||||
[assembly: AssemblyTitle("S7.Net")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("Microsoft")]
|
||||
[assembly: AssemblyProduct("S7.Net")]
|
||||
[assembly: AssemblyCopyright("Copyright © Microsoft 2009")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Durch Festlegen von ComVisible auf "false" werden die Typen in dieser Assembly unsichtbar
|
||||
// für COM-Komponenten. Wenn Sie auf einen Typ in dieser Assembly von
|
||||
// COM zugreifen müssen, legen Sie das ComVisible-Attribut für diesen Typ auf "true" fest.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// Die folgende GUID bestimmt die ID der Typbibliothek, wenn dieses Projekt für COM verfügbar gemacht wird
|
||||
[assembly: Guid("1c01e753-a660-4c35-a681-c6f6a7deee83")]
|
||||
|
||||
// Versionsinformationen für eine Assembly bestehen aus den folgenden vier Werten:
|
||||
//
|
||||
// Hauptversion
|
||||
// Nebenversion
|
||||
// Buildnummer
|
||||
// Revision
|
||||
//
|
||||
// Sie können alle Werte angeben oder die standardmäßigen Build- und Revisionsnummern
|
||||
// übernehmen, indem Sie "*" eingeben:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
||||
[assembly: InternalsVisibleTo("S7.Net.UnitTest, PublicKey=00240000048000009400000006020000002400005253413100040000010001002d1032db55f60d64bf90ea1cc2247b5a8b9b6168a07bcd464a07ce2e425d027ff9409a64ba0e3f37718e14c50cf964d0d921e5ae8b8d74bd8a82431794f897cebf0ee668feb2ccd030153611b2808fcb7785c5e5136a98e0ec23de3c1ed385d2026c26e4bed5805ff9db7e0544f59b1f19d369d43403a624586795926e38c48d")]
|
||||
|
||||
69
S7.Net/Protocol/ConnectionRequest.cs
Normal file
69
S7.Net/Protocol/ConnectionRequest.cs
Normal file
@@ -0,0 +1,69 @@
|
||||
using System;
|
||||
|
||||
namespace S7.Net.Protocol
|
||||
{
|
||||
internal static class ConnectionRequest
|
||||
{
|
||||
public static byte[] GetCOTPConnectionRequest(CpuType cpu, Int16 rack, Int16 slot)
|
||||
{
|
||||
byte[] bSend1 = {
|
||||
3, 0, 0, 22, //TPKT
|
||||
17, //COTP Header Length
|
||||
224, //Connect Request
|
||||
0, 0, //Destination Reference
|
||||
0, 46, //Source Reference
|
||||
0, //Flags
|
||||
193, //Parameter Code (src-tasp)
|
||||
2, //Parameter Length
|
||||
1, 0, //Source TASP
|
||||
194, //Parameter Code (dst-tasp)
|
||||
2, //Parameter Length
|
||||
3, 0, //Destination TASP
|
||||
192, //Parameter Code (tpdu-size)
|
||||
1, //Parameter Length
|
||||
10 //TPDU Size (2^10 = 1024)
|
||||
};
|
||||
|
||||
switch (cpu)
|
||||
{
|
||||
case CpuType.S7200:
|
||||
//S7200: Chr(193) & Chr(2) & Chr(16) & Chr(0) 'Eigener Tsap
|
||||
bSend1[13] = 0x10;
|
||||
bSend1[14] = 0x00;
|
||||
//S7200: Chr(194) & Chr(2) & Chr(16) & Chr(0) 'Fremder Tsap
|
||||
bSend1[17] = 0x10;
|
||||
bSend1[18] = 0x00;
|
||||
break;
|
||||
case CpuType.Logo0BA8:
|
||||
// These values are taken from NodeS7, it's not verified if these are
|
||||
// exact requirements to connect to the Logo0BA8.
|
||||
bSend1[13] = 0x01;
|
||||
bSend1[14] = 0x00;
|
||||
bSend1[17] = 0x01;
|
||||
bSend1[18] = 0x02;
|
||||
break;
|
||||
case CpuType.S71200:
|
||||
case CpuType.S7300:
|
||||
case CpuType.S7400:
|
||||
//S7300: Chr(193) & Chr(2) & Chr(1) & Chr(0) 'Eigener Tsap
|
||||
bSend1[13] = 0x01;
|
||||
bSend1[14] = 0x00;
|
||||
//S7300: Chr(194) & Chr(2) & Chr(3) & Chr(2) 'Fremder Tsap
|
||||
bSend1[17] = 0x03;
|
||||
bSend1[18] = (byte) ((rack << 5) | (int) slot);
|
||||
break;
|
||||
case CpuType.S71500:
|
||||
// Eigener Tsap
|
||||
bSend1[13] = 0x10;
|
||||
bSend1[14] = 0x02;
|
||||
// Fredmer Tsap
|
||||
bSend1[17] = 0x03;
|
||||
bSend1[18] = (byte) ((rack << 5) | (int) slot);
|
||||
break;
|
||||
default:
|
||||
throw new Exception("Wrong CPU Type Secified");
|
||||
}
|
||||
return bSend1;
|
||||
}
|
||||
}
|
||||
}
|
||||
15
S7.Net/Protocol/ReadWriteErrorCode.cs
Normal file
15
S7.Net/Protocol/ReadWriteErrorCode.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
|
||||
namespace S7.Net.Protocol
|
||||
{
|
||||
internal enum ReadWriteErrorCode : byte
|
||||
{
|
||||
Reserved = 0x00,
|
||||
HardwareFault = 0x01,
|
||||
AccessingObjectNotAllowed = 0x03,
|
||||
AddressOutOfRange = 0x05,
|
||||
DataTypeNotSupported = 0x06,
|
||||
DataTypeInconsistent = 0x07,
|
||||
ObjectDoesNotExist = 0x0a,
|
||||
Success = 0xff
|
||||
}
|
||||
}
|
||||
37
S7.Net/Protocol/S7/DataItemAddress.cs
Normal file
37
S7.Net/Protocol/S7/DataItemAddress.cs
Normal file
@@ -0,0 +1,37 @@
|
||||
namespace S7.Net.Protocol.S7
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents an area of memory in the PLC
|
||||
/// </summary>
|
||||
internal class DataItemAddress
|
||||
{
|
||||
public DataItemAddress(DataType dataType, int db, int startByteAddress, int byteLength)
|
||||
{
|
||||
DataType = dataType;
|
||||
DB = db;
|
||||
StartByteAddress = startByteAddress;
|
||||
ByteLength = byteLength;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Memory area to read
|
||||
/// </summary>
|
||||
public DataType DataType { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Address of memory area to read (example: for DB1 this value is 1, for T45 this value is 45)
|
||||
/// </summary>
|
||||
public int DB { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Address of the first byte to read
|
||||
/// </summary>
|
||||
public int StartByteAddress { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Length of data to read
|
||||
/// </summary>
|
||||
public int ByteLength { get; }
|
||||
}
|
||||
}
|
||||
163
S7.Net/Protocol/S7WriteMultiple.cs
Normal file
163
S7.Net/Protocol/S7WriteMultiple.cs
Normal file
@@ -0,0 +1,163 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using S7.Net.Types;
|
||||
|
||||
namespace S7.Net.Protocol
|
||||
{
|
||||
internal static class S7WriteMultiple
|
||||
{
|
||||
public static int CreateRequest(ByteArray message, DataItem[] dataItems)
|
||||
{
|
||||
message.Add(Header.Template);
|
||||
|
||||
message[Header.Offsets.ParameterCount] = (byte) dataItems.Length;
|
||||
var paramSize = dataItems.Length * Parameter.Template.Length;
|
||||
|
||||
Serialization.SetWordAt(message, Header.Offsets.ParameterSize,
|
||||
(ushort) (2 + paramSize));
|
||||
|
||||
var paramOffset = Header.Template.Length;
|
||||
var data = new ByteArray();
|
||||
|
||||
var itemCount = 0;
|
||||
|
||||
foreach (var item in dataItems)
|
||||
{
|
||||
itemCount++;
|
||||
message.Add(Parameter.Template);
|
||||
var value = Serialization.SerializeDataItem(item);
|
||||
var wordLen = item.Value is bool ? 1 : 2;
|
||||
|
||||
message[paramOffset + Parameter.Offsets.WordLength] = (byte) wordLen;
|
||||
Serialization.SetWordAt(message, paramOffset + Parameter.Offsets.Amount, (ushort) value.Length);
|
||||
Serialization.SetWordAt(message, paramOffset + Parameter.Offsets.DbNumber, (ushort) item.DB);
|
||||
message[paramOffset + Parameter.Offsets.Area] = (byte) item.DataType;
|
||||
|
||||
data.Add(0x00);
|
||||
if (item.Value is bool b)
|
||||
{
|
||||
if (item.BitAdr > 7)
|
||||
throw new ArgumentException(
|
||||
$"Cannot read bit with invalid {nameof(item.BitAdr)} '{item.BitAdr}'.", nameof(dataItems));
|
||||
|
||||
Serialization.SetAddressAt(message, paramOffset + Parameter.Offsets.Address, item.StartByteAdr,
|
||||
item.BitAdr);
|
||||
|
||||
data.Add(0x03);
|
||||
data.AddWord(1);
|
||||
|
||||
data.Add(b ? (byte)1 : (byte)0);
|
||||
if (itemCount != dataItems.Length) {
|
||||
data.Add(0);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Serialization.SetAddressAt(message, paramOffset + Parameter.Offsets.Address, item.StartByteAdr, 0);
|
||||
|
||||
var len = value.Length;
|
||||
data.Add(0x04);
|
||||
data.AddWord((ushort) (len << 3));
|
||||
data.Add(value);
|
||||
|
||||
if ((len & 0b1) == 1 && itemCount != dataItems.Length)
|
||||
{
|
||||
data.Add(0);
|
||||
}
|
||||
}
|
||||
|
||||
paramOffset += Parameter.Template.Length;
|
||||
}
|
||||
|
||||
message.Add(data.Array);
|
||||
|
||||
Serialization.SetWordAt(message, Header.Offsets.MessageLength, (ushort) message.Length);
|
||||
Serialization.SetWordAt(message, Header.Offsets.DataLength, (ushort) (message.Length - paramOffset));
|
||||
|
||||
return message.Length;
|
||||
}
|
||||
|
||||
public static void ParseResponse(byte[] message, int length, DataItem[] dataItems)
|
||||
{
|
||||
if (length < 12) throw new Exception("Not enough data received to parse write response.");
|
||||
|
||||
var messageError = Serialization.GetWordAt(message, 10);
|
||||
if (messageError != 0)
|
||||
throw new Exception($"Write failed with error {messageError}.");
|
||||
|
||||
if (length < 14 + dataItems.Length)
|
||||
throw new Exception("Not enough data received to parse individual item responses.");
|
||||
|
||||
IList<byte> itemResults = new ArraySegment<byte>(message, 14, dataItems.Length);
|
||||
|
||||
List<Exception>? errors = null;
|
||||
|
||||
for (int i = 0; i < dataItems.Length; i++)
|
||||
{
|
||||
try
|
||||
{
|
||||
Plc.ValidateResponseCode((ReadWriteErrorCode)itemResults[i]);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
if (errors == null) errors = new List<Exception>();
|
||||
errors.Add(new Exception($"Write of dataItem {dataItems[i]} failed: {e.Message}."));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (errors != null)
|
||||
throw new AggregateException(
|
||||
$"Write failed for {errors.Count} items. See the innerExceptions for details.", errors);
|
||||
}
|
||||
|
||||
private static class Header
|
||||
{
|
||||
public static byte[] Template { get; } =
|
||||
{
|
||||
0x03, 0x00, 0x00, 0x00, // TPKT
|
||||
0x02, 0xf0, 0x80, // ISO DT
|
||||
0x32, // S7 protocol ID
|
||||
0x01, // JobRequest
|
||||
0x00, 0x00, // Reserved
|
||||
0x05, 0x00, // PDU reference
|
||||
0x00, 0x0e, // Parameters length
|
||||
0x00, 0x00, // Data length
|
||||
0x05, // Function: Write var
|
||||
0x00, // Number of items to write
|
||||
};
|
||||
|
||||
public static class Offsets
|
||||
{
|
||||
public const int MessageLength = 2;
|
||||
public const int ParameterSize = 13;
|
||||
public const int DataLength = 15;
|
||||
public const int ParameterCount = 18;
|
||||
}
|
||||
}
|
||||
|
||||
private static class Parameter
|
||||
{
|
||||
public static byte[] Template { get; } =
|
||||
{
|
||||
0x12, // Spec
|
||||
0x0a, // Length of remaining bytes
|
||||
0x10, // Addressing mode
|
||||
0x02, // Transport size
|
||||
0x00, 0x00, // Number of elements
|
||||
0x00, 0x00, // DB number
|
||||
0x84, // Area type
|
||||
0x00, 0x00, 0x00 // Area offset
|
||||
};
|
||||
|
||||
public static class Offsets
|
||||
{
|
||||
public const int WordLength = 3;
|
||||
public const int Amount = 4;
|
||||
public const int DbNumber = 6;
|
||||
public const int Area = 8;
|
||||
public const int Address = 9;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
98
S7.Net/Protocol/Serialization.cs
Normal file
98
S7.Net/Protocol/Serialization.cs
Normal file
@@ -0,0 +1,98 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using S7.Net.Types;
|
||||
|
||||
namespace S7.Net.Protocol
|
||||
{
|
||||
internal static class Serialization
|
||||
{
|
||||
public static ushort GetWordAt(IList<byte> buf, int index)
|
||||
{
|
||||
return (ushort)((buf[index] << 8) + buf[index]);
|
||||
}
|
||||
|
||||
public static byte[] SerializeDataItem(DataItem dataItem)
|
||||
{
|
||||
if (dataItem.Value == null)
|
||||
{
|
||||
throw new Exception($"DataItem.Value is null, cannot serialize. StartAddr={dataItem.StartByteAdr} VarType={dataItem.VarType}");
|
||||
}
|
||||
|
||||
if (dataItem.Value is string s)
|
||||
return dataItem.VarType switch
|
||||
{
|
||||
VarType.S7String => S7String.ToByteArray(s, dataItem.Count),
|
||||
VarType.S7WString => S7WString.ToByteArray(s, dataItem.Count),
|
||||
_ => Types.String.ToByteArray(s, dataItem.Count)
|
||||
};
|
||||
|
||||
return SerializeValue(dataItem.Value);
|
||||
}
|
||||
|
||||
public static byte[] SerializeValue(object value)
|
||||
{
|
||||
switch (value.GetType().Name)
|
||||
{
|
||||
case "Boolean":
|
||||
return new[] { (byte)((bool)value ? 1 : 0) };
|
||||
case "Byte":
|
||||
return Types.Byte.ToByteArray((byte)value);
|
||||
case "Int16":
|
||||
return Types.Int.ToByteArray((Int16)value);
|
||||
case "UInt16":
|
||||
return Types.Word.ToByteArray((UInt16)value);
|
||||
case "Int32":
|
||||
return Types.DInt.ToByteArray((Int32)value);
|
||||
case "UInt32":
|
||||
return Types.DWord.ToByteArray((UInt32)value);
|
||||
case "Single":
|
||||
return Types.Real.ToByteArray((float)value);
|
||||
case "Double":
|
||||
return Types.LReal.ToByteArray((double)value);
|
||||
case "DateTime":
|
||||
return Types.DateTime.ToByteArray((System.DateTime)value);
|
||||
case "Byte[]":
|
||||
return (byte[])value;
|
||||
case "Int16[]":
|
||||
return Types.Int.ToByteArray((Int16[])value);
|
||||
case "UInt16[]":
|
||||
return Types.Word.ToByteArray((UInt16[])value);
|
||||
case "Int32[]":
|
||||
return Types.DInt.ToByteArray((Int32[])value);
|
||||
case "UInt32[]":
|
||||
return Types.DWord.ToByteArray((UInt32[])value);
|
||||
case "Single[]":
|
||||
return Types.Real.ToByteArray((float[])value);
|
||||
case "Double[]":
|
||||
return Types.LReal.ToByteArray((double[])value);
|
||||
case "String":
|
||||
// Hack: This is backwards compatible with the old code, but functionally it's broken
|
||||
// if the consumer does not pay attention to string length.
|
||||
var stringVal = (string)value;
|
||||
return Types.String.ToByteArray(stringVal, stringVal.Length);
|
||||
case "DateTime[]":
|
||||
return Types.DateTime.ToByteArray((System.DateTime[])value);
|
||||
case "DateTimeLong[]":
|
||||
return Types.DateTimeLong.ToByteArray((System.DateTime[])value);
|
||||
default:
|
||||
throw new InvalidVariableTypeException();
|
||||
}
|
||||
}
|
||||
|
||||
public static void SetAddressAt(ByteArray buffer, int index, int startByte, byte bitNumber)
|
||||
{
|
||||
var start = startByte * 8 + bitNumber;
|
||||
buffer[index + 2] = (byte)start;
|
||||
start >>= 8;
|
||||
buffer[index + 1] = (byte)start;
|
||||
start >>= 8;
|
||||
buffer[index] = (byte)start;
|
||||
}
|
||||
|
||||
public static void SetWordAt(ByteArray buffer, int index, ushort value)
|
||||
{
|
||||
buffer[index] = (byte)(value >> 8);
|
||||
buffer[index + 1] = (byte)value;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,122 +1,33 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProductVersion>9.0.30729</ProductVersion>
|
||||
<SchemaVersion>2.0</SchemaVersion>
|
||||
<ProjectGuid>{BFD484F9-3F04-42A2-BF2A-60A189A25DCF}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>S7.Net</RootNamespace>
|
||||
<AssemblyName>S7.Net</AssemblyName>
|
||||
<TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<FileUpgradeFlags>
|
||||
</FileUpgradeFlags>
|
||||
<UpgradeBackupLocation>
|
||||
</UpgradeBackupLocation>
|
||||
<OldToolsVersion>3.5</OldToolsVersion>
|
||||
<PublishUrl>publish\</PublishUrl>
|
||||
<Install>true</Install>
|
||||
<InstallFrom>Disk</InstallFrom>
|
||||
<UpdateEnabled>false</UpdateEnabled>
|
||||
<UpdateMode>Foreground</UpdateMode>
|
||||
<UpdateInterval>7</UpdateInterval>
|
||||
<UpdateIntervalUnits>Days</UpdateIntervalUnits>
|
||||
<UpdatePeriodically>false</UpdatePeriodically>
|
||||
<UpdateRequired>false</UpdateRequired>
|
||||
<MapFileExtensions>true</MapFileExtensions>
|
||||
<ApplicationRevision>0</ApplicationRevision>
|
||||
<ApplicationVersion>1.0.0.%2a</ApplicationVersion>
|
||||
<IsWebBootstrapper>false</IsWebBootstrapper>
|
||||
<UseApplicationTrust>false</UseApplicationTrust>
|
||||
<BootstrapperEnabled>true</BootstrapperEnabled>
|
||||
<TargetFrameworkProfile />
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<Prefer32Bit>false</Prefer32Bit>
|
||||
<DocumentationFile>bin\Debug\S7.Net.xml</DocumentationFile>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<Prefer32Bit>false</Prefer32Bit>
|
||||
<DocumentationFile>bin\Release\S7.Net.xml</DocumentationFile>
|
||||
</PropertyGroup>
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net452;netstandard2.0;netstandard1.3</TargetFrameworks>
|
||||
<SignAssembly>true</SignAssembly>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<AssemblyOriginatorKeyFile>Properties\S7.Net.snk</AssemblyOriginatorKeyFile>
|
||||
<InternalsVisibleTo>S7.Net.UnitTest</InternalsVisibleTo>
|
||||
|
||||
<PackageId>S7netplus</PackageId>
|
||||
<Title>S7.Net Plus</Title>
|
||||
<Description>A continuation of Juergen1969's Siemens communication library.</Description>
|
||||
<Authors>Derek Heiser;Michele Cattafesta;Michael Croes;Raphael Schlameuß</Authors>
|
||||
<PackageProjectUrl>https://github.com/killnine/s7netplus</PackageProjectUrl>
|
||||
<RepositoryUrl>https://github.com/killnine/s7netplus</RepositoryUrl>
|
||||
<RepositoryType>git</RepositoryType>
|
||||
<PackageTags>PLC Siemens Communication S7</PackageTags>
|
||||
<Copyright>Derek Heiser 2015</Copyright>
|
||||
<LangVersion>8.0</LangVersion>
|
||||
<Nullable>Enable</Nullable>
|
||||
<DebugType>portable</DebugType>
|
||||
<IncludeSymbols>true</IncludeSymbols>
|
||||
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
|
||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(TargetFramework)' == 'net452' Or '$(TargetFramework)' == 'netstandard2.0' ">
|
||||
<DefineConstants>NET_FULL</DefineConstants>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core">
|
||||
<RequiredTargetFramework>3.5</RequiredTargetFramework>
|
||||
</Reference>
|
||||
<Reference Include="System.Xml.Linq">
|
||||
<RequiredTargetFramework>3.5</RequiredTargetFramework>
|
||||
</Reference>
|
||||
<Reference Include="System.Data.DataSetExtensions">
|
||||
<RequiredTargetFramework>3.5</RequiredTargetFramework>
|
||||
</Reference>
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Xml" />
|
||||
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0" PrivateAssets="All" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Conversion.cs" />
|
||||
<Compile Include="Enums.cs" />
|
||||
<Compile Include="PLC.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="Types\Boolean.cs" />
|
||||
<Compile Include="Types\Byte.cs" />
|
||||
<Compile Include="Types\ByteArray.cs" />
|
||||
<Compile Include="Types\Class.cs" />
|
||||
<Compile Include="Types\Counter.cs" />
|
||||
<Compile Include="Types\DataItem.cs" />
|
||||
<Compile Include="Types\DInt.cs" />
|
||||
<Compile Include="Types\Double.cs" />
|
||||
<Compile Include="Types\DWord.cs" />
|
||||
<Compile Include="Types\Int.cs" />
|
||||
<Compile Include="Types\String.cs" />
|
||||
<Compile Include="Types\Struct.cs" />
|
||||
<Compile Include="Types\Timer.cs" />
|
||||
<Compile Include="Types\Word.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<BootstrapperPackage Include="Microsoft.Net.Client.3.5">
|
||||
<Visible>False</Visible>
|
||||
<ProductName>.NET Framework 3.5 SP1 Client Profile</ProductName>
|
||||
<Install>false</Install>
|
||||
</BootstrapperPackage>
|
||||
<BootstrapperPackage Include="Microsoft.Net.Framework.3.5.SP1">
|
||||
<Visible>False</Visible>
|
||||
<ProductName>.NET Framework 3.5 SP1</ProductName>
|
||||
<Install>true</Install>
|
||||
</BootstrapperPackage>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="Properties\S7.Net.snk" />
|
||||
</ItemGroup>
|
||||
<ItemGroup />
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
<Target Name="BeforeBuild">
|
||||
</Target>
|
||||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
</Project>
|
||||
</Project>
|
||||
|
||||
57
S7.Net/StreamExtensions.cs
Normal file
57
S7.Net/StreamExtensions.cs
Normal file
@@ -0,0 +1,57 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace S7.Net
|
||||
{
|
||||
/// <summary>
|
||||
/// Extensions for Streams
|
||||
/// </summary>
|
||||
public static class StreamExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Reads bytes from the stream into the buffer until exactly the requested number of bytes (or EOF) have been read
|
||||
/// </summary>
|
||||
/// <param name="stream">the Stream to read from</param>
|
||||
/// <param name="buffer">the buffer to read into</param>
|
||||
/// <param name="offset">the offset in the buffer to read into</param>
|
||||
/// <param name="count">the amount of bytes to read into the buffer</param>
|
||||
/// <returns>returns the amount of read bytes</returns>
|
||||
public static int ReadExact(this Stream stream, byte[] buffer, int offset, int count)
|
||||
{
|
||||
int read = 0;
|
||||
int received;
|
||||
do
|
||||
{
|
||||
received = stream.Read(buffer, offset + read, count - read);
|
||||
read += received;
|
||||
}
|
||||
while (read < count && received > 0);
|
||||
|
||||
return read;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads bytes from the stream into the buffer until exactly the requested number of bytes (or EOF) have been read
|
||||
/// </summary>
|
||||
/// <param name="stream">the Stream to read from</param>
|
||||
/// <param name="buffer">the buffer to read into</param>
|
||||
/// <param name="offset">the offset in the buffer to read into</param>
|
||||
/// <param name="count">the amount of bytes to read into the buffer</param>
|
||||
/// <returns>returns the amount of read bytes</returns>
|
||||
public static async Task<int> ReadExactAsync(this Stream stream, byte[] buffer, int offset, int count, CancellationToken cancellationToken)
|
||||
{
|
||||
int read = 0;
|
||||
int received;
|
||||
do
|
||||
{
|
||||
received = await stream.ReadAsync(buffer, offset + read, count - read, cancellationToken).ConfigureAwait(false);
|
||||
read += received;
|
||||
}
|
||||
while (read < count && received > 0);
|
||||
|
||||
return read;
|
||||
}
|
||||
}
|
||||
}
|
||||
94
S7.Net/TPKT.cs
Normal file
94
S7.Net/TPKT.cs
Normal file
@@ -0,0 +1,94 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace S7.Net
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Describes a TPKT Packet
|
||||
/// </summary>
|
||||
internal class TPKT
|
||||
{
|
||||
|
||||
|
||||
public byte Version;
|
||||
public byte Reserved1;
|
||||
public int Length;
|
||||
public byte[] Data;
|
||||
private TPKT(byte version, byte reserved1, int length, byte[] data)
|
||||
{
|
||||
Version = version;
|
||||
Reserved1 = reserved1;
|
||||
Length = length;
|
||||
Data = data;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads a TPKT from the socket
|
||||
/// </summary>
|
||||
/// <param name="stream">The stream to read from</param>
|
||||
/// <returns>TPKT Instance</returns>
|
||||
public static TPKT Read(Stream stream)
|
||||
{
|
||||
var buf = new byte[4];
|
||||
int len = stream.ReadExact(buf, 0, 4);
|
||||
if (len < 4) throw new TPKTInvalidException($"TPKT header is incomplete / invalid. Received Bytes: {len} expected: {buf.Length}");
|
||||
var version = buf[0];
|
||||
var reserved1 = buf[1];
|
||||
var length = buf[2] * 256 + buf[3]; //BigEndian
|
||||
|
||||
var data = new byte[length - 4];
|
||||
len = stream.ReadExact(data, 0, data.Length);
|
||||
if (len < data.Length)
|
||||
throw new TPKTInvalidException($"TPKT payload is incomplete / invalid. Received Bytes: {len} expected: {data.Length}");
|
||||
|
||||
return new TPKT
|
||||
(
|
||||
version: version,
|
||||
reserved1: reserved1,
|
||||
length: length,
|
||||
data: data
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads a TPKT from the socket Async
|
||||
/// </summary>
|
||||
/// <param name="stream">The stream to read from</param>
|
||||
/// <returns>Task TPKT Instace</returns>
|
||||
public static async Task<TPKT> ReadAsync(Stream stream, CancellationToken cancellationToken)
|
||||
{
|
||||
var buf = new byte[4];
|
||||
int len = await stream.ReadExactAsync(buf, 0, 4, cancellationToken).ConfigureAwait(false);
|
||||
if (len < 4) throw new TPKTInvalidException("TPKT is incomplete / invalid");
|
||||
|
||||
var version = buf[0];
|
||||
var reserved1 = buf[1];
|
||||
var length = buf[2] * 256 + buf[3]; //BigEndian
|
||||
|
||||
var data = new byte[length - 4];
|
||||
len = await stream.ReadExactAsync(data, 0, data.Length, cancellationToken).ConfigureAwait(false);
|
||||
if (len < data.Length)
|
||||
throw new TPKTInvalidException("TPKT payload incomplete / invalid");
|
||||
|
||||
return new TPKT
|
||||
(
|
||||
version: version,
|
||||
reserved1: reserved1,
|
||||
length: length,
|
||||
data: data
|
||||
);
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return string.Format("Version: {0} Length: {1} Data: {2}",
|
||||
Version,
|
||||
Length,
|
||||
BitConverter.ToString(Data)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
43
S7.Net/Types/Bit.cs
Normal file
43
S7.Net/Types/Bit.cs
Normal file
@@ -0,0 +1,43 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
|
||||
namespace S7.Net.Types
|
||||
{
|
||||
/// <summary>
|
||||
/// Contains the conversion methods to convert Bit from S7 plc to C#.
|
||||
/// </summary>
|
||||
public static class Bit
|
||||
{
|
||||
/// <summary>
|
||||
/// Converts a Bit to bool
|
||||
/// </summary>
|
||||
public static bool FromByte(byte v, byte bitAdr)
|
||||
{
|
||||
return (((int)v & (1 << bitAdr)) != 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts an array of bytes to a BitArray.
|
||||
/// </summary>
|
||||
/// <param name="bytes">The bytes to convert.</param>
|
||||
/// <returns>A BitArray with the same number of bits and equal values as <paramref name="bytes"/>.</returns>
|
||||
public static BitArray ToBitArray(byte[] bytes) => ToBitArray(bytes, bytes.Length * 8);
|
||||
|
||||
/// <summary>
|
||||
/// Converts an array of bytes to a BitArray.
|
||||
/// </summary>
|
||||
/// <param name="bytes">The bytes to convert.</param>
|
||||
/// <param name="length">The number of bits to return.</param>
|
||||
/// <returns>A BitArray with <paramref name="length"/> bits.</returns>
|
||||
public static BitArray ToBitArray(byte[] bytes, int length)
|
||||
{
|
||||
if (length > bytes.Length * 8) throw new ArgumentException($"Not enough data in bytes to return {length} bits.", nameof(bytes));
|
||||
|
||||
var bitArr = new BitArray(bytes);
|
||||
var bools = new bool[length];
|
||||
for (var i = 0; i < length; i++) bools[i] = bitArr[i];
|
||||
|
||||
return new BitArray(bools);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,4 @@
|
||||
using System;
|
||||
|
||||
namespace S7.Net.Types
|
||||
namespace S7.Net.Types
|
||||
{
|
||||
/// <summary>
|
||||
/// Contains the methods to read, set and reset bits inside bytes
|
||||
@@ -12,10 +10,7 @@ namespace S7.Net.Types
|
||||
/// </summary>
|
||||
public static bool GetValue(byte value, int bit)
|
||||
{
|
||||
if ((value & (int)Math.Pow(2, bit)) != 0)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
return (((int)value & (1 << bit)) != 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -23,7 +18,7 @@ namespace S7.Net.Types
|
||||
/// </summary>
|
||||
public static byte SetBit(byte value, int bit)
|
||||
{
|
||||
return (byte)(value | (byte)Math.Pow(2, bit));
|
||||
return (byte)((value | (1 << bit)) & 0xFF);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -31,7 +26,7 @@ namespace S7.Net.Types
|
||||
/// </summary>
|
||||
public static byte ClearBit(byte value, int bit)
|
||||
{
|
||||
return (byte)(value & (byte)(~(byte)Math.Pow(2, bit)));
|
||||
return (byte)((value | (~(1 << bit))) & 0xFF);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -12,8 +12,7 @@ namespace S7.Net.Types
|
||||
/// </summary>
|
||||
public static byte[] ToByteArray(byte value)
|
||||
{
|
||||
byte[] bytes = new byte[] { value};
|
||||
return bytes;
|
||||
return new byte[] { value }; ;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -6,11 +6,19 @@ namespace S7.Net.Types
|
||||
{
|
||||
List<byte> list = new List<byte>();
|
||||
|
||||
public byte[] array
|
||||
public byte this[int index]
|
||||
{
|
||||
get => list[index];
|
||||
set => list[index] = value;
|
||||
}
|
||||
|
||||
public byte[] Array
|
||||
{
|
||||
get { return list.ToArray(); }
|
||||
}
|
||||
|
||||
public int Length => list.Count;
|
||||
|
||||
public ByteArray()
|
||||
{
|
||||
list = new List<byte>();
|
||||
@@ -31,14 +39,25 @@ namespace S7.Net.Types
|
||||
list.Add(item);
|
||||
}
|
||||
|
||||
public void AddWord(ushort value)
|
||||
{
|
||||
list.Add((byte) (value >> 8));
|
||||
list.Add((byte) value);
|
||||
}
|
||||
|
||||
public void Add(byte[] items)
|
||||
{
|
||||
list.AddRange(items);
|
||||
}
|
||||
|
||||
public void Add(IEnumerable<byte> items)
|
||||
{
|
||||
list.AddRange(items);
|
||||
}
|
||||
|
||||
public void Add(ByteArray byteArray)
|
||||
{
|
||||
list.AddRange(byteArray.array);
|
||||
list.AddRange(byteArray.Array);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,8 +13,8 @@ namespace S7.Net.Types
|
||||
private static IEnumerable<PropertyInfo> GetAccessableProperties(Type classType)
|
||||
{
|
||||
return classType
|
||||
#if NETFX_CORE
|
||||
.GetProperties().Where(p => p.GetSetMethod() != null);
|
||||
#if NETSTANDARD1_3
|
||||
.GetTypeInfo().DeclaredProperties.Where(p => p.SetMethod != null);
|
||||
#else
|
||||
.GetProperties(
|
||||
BindingFlags.SetProperty |
|
||||
@@ -25,10 +25,8 @@ namespace S7.Net.Types
|
||||
|
||||
}
|
||||
|
||||
private static double GetIncreasedNumberOfBytes(double startingNumberOfBytes, Type type)
|
||||
private static double GetIncreasedNumberOfBytes(double numBytes, Type type)
|
||||
{
|
||||
double numBytes = startingNumberOfBytes;
|
||||
|
||||
switch (type.Name)
|
||||
{
|
||||
case "Boolean":
|
||||
@@ -52,16 +50,21 @@ namespace S7.Net.Types
|
||||
numBytes++;
|
||||
numBytes += 4;
|
||||
break;
|
||||
case "Float":
|
||||
case "Double":
|
||||
case "Single":
|
||||
numBytes = Math.Ceiling(numBytes);
|
||||
if ((numBytes / 2 - Math.Floor(numBytes / 2.0)) > 0)
|
||||
numBytes++;
|
||||
numBytes += 4;
|
||||
break;
|
||||
case "Double":
|
||||
numBytes = Math.Ceiling(numBytes);
|
||||
if ((numBytes / 2 - Math.Floor(numBytes / 2.0)) > 0)
|
||||
numBytes++;
|
||||
numBytes += 8;
|
||||
break;
|
||||
default:
|
||||
var propertyClass = Activator.CreateInstance(type);
|
||||
numBytes += GetClassSize(propertyClass);
|
||||
numBytes = GetClassSize(propertyClass, numBytes, true);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -73,10 +76,8 @@ namespace S7.Net.Types
|
||||
/// </summary>
|
||||
/// <param name="instance">An instance of the class</param>
|
||||
/// <returns>the number of bytes</returns>
|
||||
public static int GetClassSize(object instance)
|
||||
public static double GetClassSize(object instance, double numBytes = 0.0, bool isInnerProperty = false)
|
||||
{
|
||||
double numBytes = 0.0;
|
||||
|
||||
var properties = GetAccessableProperties(instance.GetType());
|
||||
foreach (var property in properties)
|
||||
{
|
||||
@@ -89,6 +90,7 @@ namespace S7.Net.Types
|
||||
throw new Exception("Cannot determine size of class, because an array is defined which has no fixed size greater than zero.");
|
||||
}
|
||||
|
||||
IncrementToEven(ref numBytes);
|
||||
for (int i = 0; i < array.Length; i++)
|
||||
{
|
||||
numBytes = GetIncreasedNumberOfBytes(numBytes, elementType);
|
||||
@@ -99,12 +101,19 @@ namespace S7.Net.Types
|
||||
numBytes = GetIncreasedNumberOfBytes(numBytes, property.PropertyType);
|
||||
}
|
||||
}
|
||||
return (int)numBytes;
|
||||
if (false == isInnerProperty)
|
||||
{
|
||||
// enlarge numBytes to next even number because S7-Structs in a DB always will be resized to an even byte count
|
||||
numBytes = Math.Ceiling(numBytes);
|
||||
if ((numBytes / 2 - Math.Floor(numBytes / 2.0)) > 0)
|
||||
numBytes++;
|
||||
}
|
||||
return numBytes;
|
||||
}
|
||||
|
||||
private static object GetPropertyValue(Type propertyType, byte[] bytes, ref double numBytes)
|
||||
private static object? GetPropertyValue(Type propertyType, byte[] bytes, ref double numBytes)
|
||||
{
|
||||
object value = null;
|
||||
object? value = null;
|
||||
|
||||
switch (propertyType.Name)
|
||||
{
|
||||
@@ -164,12 +173,12 @@ namespace S7.Net.Types
|
||||
bytes[(int)numBytes + 3]);
|
||||
numBytes += 4;
|
||||
break;
|
||||
case "Double":
|
||||
case "Single":
|
||||
numBytes = Math.Ceiling(numBytes);
|
||||
if ((numBytes / 2 - Math.Floor(numBytes / 2.0)) > 0)
|
||||
numBytes++;
|
||||
// hier auswerten
|
||||
value = Double.FromByteArray(
|
||||
value = Real.FromByteArray(
|
||||
new byte[] {
|
||||
bytes[(int)numBytes],
|
||||
bytes[(int)numBytes + 1],
|
||||
@@ -177,16 +186,20 @@ namespace S7.Net.Types
|
||||
bytes[(int)numBytes + 3] });
|
||||
numBytes += 4;
|
||||
break;
|
||||
case "Double":
|
||||
numBytes = Math.Ceiling(numBytes);
|
||||
if ((numBytes / 2 - Math.Floor(numBytes / 2.0)) > 0)
|
||||
numBytes++;
|
||||
var buffer = new byte[8];
|
||||
Array.Copy(bytes, (int)numBytes, buffer, 0, 8);
|
||||
// hier auswerten
|
||||
value = LReal.FromByteArray(buffer);
|
||||
numBytes += 8;
|
||||
break;
|
||||
default:
|
||||
var propClass = Activator.CreateInstance(propertyType);
|
||||
var buffer = new byte[GetClassSize(propClass)];
|
||||
if (buffer.Length > 0)
|
||||
{
|
||||
Buffer.BlockCopy(bytes, (int)Math.Ceiling(numBytes), buffer, 0, buffer.Length);
|
||||
FromBytes(propClass, buffer);
|
||||
value = propClass;
|
||||
numBytes += buffer.Length;
|
||||
}
|
||||
numBytes = FromBytes(propClass, bytes, numBytes);
|
||||
value = propClass;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -198,16 +211,10 @@ namespace S7.Net.Types
|
||||
/// </summary>
|
||||
/// <param name="sourceClass">The object to fill in the given array of bytes</param>
|
||||
/// <param name="bytes">The array of bytes</param>
|
||||
public static void FromBytes(object sourceClass, byte[] bytes)
|
||||
public static double FromBytes(object sourceClass, byte[] bytes, double numBytes = 0, bool isInnerClass = false)
|
||||
{
|
||||
if (bytes == null)
|
||||
return;
|
||||
|
||||
if (bytes.Length != GetClassSize(sourceClass))
|
||||
return;
|
||||
|
||||
// and decode it
|
||||
double numBytes = 0.0;
|
||||
return numBytes;
|
||||
|
||||
var properties = GetAccessableProperties(sourceClass.GetType());
|
||||
foreach (var property in properties)
|
||||
@@ -215,6 +222,7 @@ namespace S7.Net.Types
|
||||
if (property.PropertyType.IsArray)
|
||||
{
|
||||
Array array = (Array)property.GetValue(sourceClass, null);
|
||||
IncrementToEven(ref numBytes);
|
||||
Type elementType = property.PropertyType.GetElementType();
|
||||
for (int i = 0; i < array.Length && numBytes < bytes.Length; i++)
|
||||
{
|
||||
@@ -231,13 +239,15 @@ namespace S7.Net.Types
|
||||
null);
|
||||
}
|
||||
}
|
||||
|
||||
return numBytes;
|
||||
}
|
||||
|
||||
private static void ToBytes(object propertyValue, byte[] bytes, ref double numBytes)
|
||||
private static double SetBytesFromProperty(object propertyValue, byte[] bytes, double numBytes)
|
||||
{
|
||||
int bytePos = 0;
|
||||
int bitPos = 0;
|
||||
byte[] bytes2 = null;
|
||||
byte[]? bytes2 = null;
|
||||
|
||||
switch (propertyValue.GetType().Name)
|
||||
{
|
||||
@@ -269,25 +279,28 @@ namespace S7.Net.Types
|
||||
case "UInt32":
|
||||
bytes2 = DWord.ToByteArray((UInt32)propertyValue);
|
||||
break;
|
||||
case "Single":
|
||||
bytes2 = Real.ToByteArray((float)propertyValue);
|
||||
break;
|
||||
case "Double":
|
||||
bytes2 = Double.ToByteArray((double)propertyValue);
|
||||
bytes2 = LReal.ToByteArray((double)propertyValue);
|
||||
break;
|
||||
default:
|
||||
bytes2 = ToBytes(propertyValue);
|
||||
numBytes = ToBytes(propertyValue, bytes, numBytes);
|
||||
break;
|
||||
}
|
||||
|
||||
if (bytes2 != null)
|
||||
{
|
||||
// add them
|
||||
numBytes = Math.Ceiling(numBytes);
|
||||
if ((numBytes / 2 - Math.Floor(numBytes / 2.0)) > 0)
|
||||
numBytes++;
|
||||
IncrementToEven(ref numBytes);
|
||||
|
||||
bytePos = (int)numBytes;
|
||||
for (int bCnt = 0; bCnt < bytes2.Length; bCnt++)
|
||||
bytes[bytePos + bCnt] = bytes2[bCnt];
|
||||
numBytes += bytes2.Length;
|
||||
}
|
||||
|
||||
return numBytes;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -295,30 +308,33 @@ namespace S7.Net.Types
|
||||
/// </summary>
|
||||
/// <param name="sourceClass">The struct object</param>
|
||||
/// <returns>A byte array or null if fails.</returns>
|
||||
public static byte[] ToBytes(object sourceClass)
|
||||
public static double ToBytes(object sourceClass, byte[] bytes, double numBytes = 0.0)
|
||||
{
|
||||
int size = GetClassSize(sourceClass);
|
||||
byte[] bytes = new byte[size];
|
||||
double numBytes = 0.0;
|
||||
|
||||
var properties = GetAccessableProperties(sourceClass.GetType());
|
||||
foreach (var property in properties)
|
||||
{
|
||||
if (property.PropertyType.IsArray)
|
||||
{
|
||||
Array array = (Array)property.GetValue(sourceClass, null);
|
||||
IncrementToEven(ref numBytes);
|
||||
Type elementType = property.PropertyType.GetElementType();
|
||||
for (int i = 0; i < array.Length && numBytes < bytes.Length; i++)
|
||||
{
|
||||
ToBytes(array.GetValue(i), bytes, ref numBytes);
|
||||
numBytes = SetBytesFromProperty(array.GetValue(i), bytes, numBytes);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ToBytes(property.GetValue(sourceClass, null), bytes, ref numBytes);
|
||||
numBytes = SetBytesFromProperty(property.GetValue(sourceClass, null), bytes, numBytes);
|
||||
}
|
||||
}
|
||||
return bytes;
|
||||
return numBytes;
|
||||
}
|
||||
|
||||
private static void IncrementToEven(ref double numBytes)
|
||||
{
|
||||
numBytes = Math.Ceiling(numBytes);
|
||||
if (numBytes % 2 > 0) numBytes++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,16 +18,9 @@ namespace S7.Net.Types
|
||||
}
|
||||
// bytes[0] -> HighByte
|
||||
// bytes[1] -> LowByte
|
||||
return FromBytes(bytes[1], bytes[0]);
|
||||
return (UInt16)((bytes[0] << 8) | bytes[1]);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts a Counter (2 bytes) to ushort (UInt16)
|
||||
/// </summary>
|
||||
public static UInt16 FromBytes(byte LoVal, byte HiVal)
|
||||
{
|
||||
return (UInt16)(HiVal * 256 + LoVal);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts a ushort (UInt16) to word (2 bytes)
|
||||
@@ -35,16 +28,10 @@ namespace S7.Net.Types
|
||||
public static byte[] ToByteArray(UInt16 value)
|
||||
{
|
||||
byte[] bytes = new byte[2];
|
||||
int x = 2;
|
||||
long valLong = (long)((UInt16)value);
|
||||
for (int cnt = 0; cnt < x; cnt++)
|
||||
{
|
||||
Int64 x1 = (Int64)Math.Pow(256, (cnt));
|
||||
|
||||
Int64 x3 = (Int64)(valLong / x1);
|
||||
bytes[x - cnt - 1] = (byte)(x3 & 255);
|
||||
valLong -= bytes[x - cnt - 1] * x1;
|
||||
}
|
||||
bytes[0] = (byte)((value << 8) & 0xFF);
|
||||
bytes[1] = (byte)((value) & 0xFF);
|
||||
|
||||
return bytes;
|
||||
}
|
||||
|
||||
@@ -56,7 +43,7 @@ namespace S7.Net.Types
|
||||
ByteArray arr = new ByteArray();
|
||||
foreach (UInt16 val in value)
|
||||
arr.Add(ToByteArray(val));
|
||||
return arr.array;
|
||||
return arr.Array;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -16,16 +16,9 @@ namespace S7.Net.Types
|
||||
{
|
||||
throw new ArgumentException("Wrong number of bytes. Bytes array must contain 4 bytes.");
|
||||
}
|
||||
return FromBytes(bytes[3], bytes[2], bytes[1], bytes[0]);
|
||||
return bytes[0] << 24 | bytes[1] << 16 | bytes[2] << 8 | bytes[3];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts a S7 DInt (4 bytes) to int (Int32)
|
||||
/// </summary>
|
||||
public static Int32 FromBytes(byte v1, byte v2, byte v3, byte v4)
|
||||
{
|
||||
return (Int32)(v1 + v2 * Math.Pow(2, 8) + v3 * Math.Pow(2, 16) + v4 * Math.Pow(2, 24));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts a int (Int32) to S7 DInt (4 bytes)
|
||||
@@ -33,16 +26,12 @@ namespace S7.Net.Types
|
||||
public static byte[] ToByteArray(Int32 value)
|
||||
{
|
||||
byte[] bytes = new byte[4];
|
||||
int x = 4;
|
||||
long valLong = (long)((Int32)value);
|
||||
for (int cnt = 0; cnt < x; cnt++)
|
||||
{
|
||||
Int64 x1 = (Int64)Math.Pow(256, (cnt));
|
||||
|
||||
Int64 x3 = (Int64)(valLong / x1);
|
||||
bytes[x - cnt - 1] = (byte)(x3 & 255);
|
||||
valLong -= bytes[x - cnt - 1] * x1;
|
||||
}
|
||||
bytes[0] = (byte)((value >> 24) & 0xFF);
|
||||
bytes[1] = (byte)((value >> 16) & 0xFF);
|
||||
bytes[2] = (byte)((value >> 8) & 0xFF);
|
||||
bytes[3] = (byte)((value) & 0xFF);
|
||||
|
||||
return bytes;
|
||||
}
|
||||
|
||||
@@ -54,7 +43,7 @@ namespace S7.Net.Types
|
||||
ByteArray arr = new ByteArray();
|
||||
foreach (Int32 val in value)
|
||||
arr.Add(ToByteArray(val));
|
||||
return arr.array;
|
||||
return arr.Array;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -71,18 +60,6 @@ namespace S7.Net.Types
|
||||
return values;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts from C# long (Int64) to C# int (Int32)
|
||||
/// </summary>
|
||||
public static Int32 CDWord(Int64 value)
|
||||
{
|
||||
if (value > Int32.MaxValue)
|
||||
{
|
||||
value -= (long)Int32.MaxValue + 1;
|
||||
value = (long)Int32.MaxValue + 1 - value;
|
||||
value *= -1;
|
||||
}
|
||||
return (int)value;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,36 +12,39 @@ namespace S7.Net.Types
|
||||
/// </summary>
|
||||
public static UInt32 FromByteArray(byte[] bytes)
|
||||
{
|
||||
return FromBytes(bytes[3], bytes[2], bytes[1], bytes[0]);
|
||||
return (UInt32)(bytes[0] << 24 | bytes[1] << 16 | bytes[2] << 8 | bytes[3]);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Converts a S7 DWord (4 bytes) to uint (UInt32)
|
||||
/// Converts 4 bytes to DWord (UInt32)
|
||||
/// </summary>
|
||||
public static UInt32 FromBytes(byte v1, byte v2, byte v3, byte v4)
|
||||
public static UInt32 FromBytes(byte b1, byte b2, byte b3, byte b4)
|
||||
{
|
||||
return (UInt32)(v1 + v2 * Math.Pow(2, 8) + v3 * Math.Pow(2, 16) + v4 * Math.Pow(2, 24));
|
||||
return (UInt32)((b4 << 24) | (b3 << 16) | (b2 << 8) | b1);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Converts a uint (UInt32) to S7 DWord (4 bytes)
|
||||
/// </summary>
|
||||
public static byte[] ToByteArray(UInt32 value)
|
||||
{
|
||||
byte[] bytes = new byte[4];
|
||||
int x = 4;
|
||||
long valLong = (long)((UInt32)value);
|
||||
for (int cnt = 0; cnt < x; cnt++)
|
||||
{
|
||||
Int64 x1 = (Int64)Math.Pow(256, (cnt));
|
||||
|
||||
Int64 x3 = (Int64)(valLong / x1);
|
||||
bytes[x - cnt - 1] = (byte)(x3 & 255);
|
||||
valLong -= bytes[x - cnt - 1] * x1;
|
||||
}
|
||||
bytes[0] = (byte)((value >> 24) & 0xFF);
|
||||
bytes[1] = (byte)((value >> 16) & 0xFF);
|
||||
bytes[2] = (byte)((value >> 8) & 0xFF);
|
||||
bytes[3] = (byte)((value) & 0xFF);
|
||||
|
||||
return bytes;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Converts an array of uint (UInt32) to an array of S7 DWord (4 bytes)
|
||||
/// </summary>
|
||||
@@ -50,7 +53,7 @@ namespace S7.Net.Types
|
||||
ByteArray arr = new ByteArray();
|
||||
foreach (UInt32 val in value)
|
||||
arr.Add(ToByteArray(val));
|
||||
return arr.array;
|
||||
return arr.Array;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
namespace S7.Net.Types
|
||||
using S7.Net.Protocol.S7;
|
||||
using System;
|
||||
|
||||
namespace S7.Net.Types
|
||||
{
|
||||
/// <summary>
|
||||
/// Create an instance of a memory block that can be read by using ReadMultipleVars
|
||||
@@ -25,6 +28,11 @@
|
||||
/// </summary>
|
||||
public int StartByteAdr { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Addess of bit to read from StartByteAdr
|
||||
/// </summary>
|
||||
public byte BitAdr { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Number of variables to read
|
||||
/// </summary>
|
||||
@@ -33,7 +41,7 @@
|
||||
/// <summary>
|
||||
/// Contains the value of the memory area after the read has been executed
|
||||
/// </summary>
|
||||
public object Value { get; set; }
|
||||
public object? Value { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Create an instance of DataItem
|
||||
@@ -43,5 +51,54 @@
|
||||
VarType = VarType.Byte;
|
||||
Count = 1;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create an instance of <see cref="DataItem"/> from the supplied address.
|
||||
/// </summary>
|
||||
/// <param name="address">The address to create the DataItem for.</param>
|
||||
/// <returns>A new <see cref="DataItem"/> instance with properties parsed from <paramref name="address"/>.</returns>
|
||||
/// <remarks>The <see cref="Count" /> property is not parsed from the address.</remarks>
|
||||
public static DataItem FromAddress(string address)
|
||||
{
|
||||
PLCAddress.Parse(address, out var dataType, out var dbNumber, out var varType, out var startByte,
|
||||
out var bitNumber);
|
||||
|
||||
return new DataItem
|
||||
{
|
||||
DataType = dataType,
|
||||
DB = dbNumber,
|
||||
VarType = varType,
|
||||
StartByteAdr = startByte,
|
||||
BitAdr = (byte) (bitNumber == -1 ? 0 : bitNumber)
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create an instance of <see cref="DataItem"/> from the supplied address and value.
|
||||
/// </summary>
|
||||
/// <param name="address">The address to create the DataItem for.</param>
|
||||
/// <param name="value">The value to be applied to the DataItem.</param>
|
||||
/// <returns>A new <see cref="DataItem"/> instance with properties parsed from <paramref name="address"/> and the supplied value set.</returns>
|
||||
public static DataItem FromAddressAndValue<T>(string address, T value)
|
||||
{
|
||||
var dataItem = FromAddress(address);
|
||||
dataItem.Value = value;
|
||||
|
||||
if (typeof(T).IsArray)
|
||||
{
|
||||
var array = ((Array?)dataItem.Value);
|
||||
if ( array != null)
|
||||
{
|
||||
dataItem.Count = array.Length;
|
||||
}
|
||||
}
|
||||
|
||||
return dataItem;
|
||||
}
|
||||
|
||||
internal static DataItemAddress GetDataItemAddress(DataItem dataItem)
|
||||
{
|
||||
return new DataItemAddress(dataItem.DataType, dataItem.DB, dataItem.StartByteAdr, Plc.VarTypeToByteLength(dataItem.VarType, dataItem.Count));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
156
S7.Net/Types/DateTime.cs
Normal file
156
S7.Net/Types/DateTime.cs
Normal file
@@ -0,0 +1,156 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace S7.Net.Types
|
||||
{
|
||||
/// <summary>
|
||||
/// Contains the methods to convert between <see cref="T:System.DateTime"/> and S7 representation of datetime values.
|
||||
/// </summary>
|
||||
public static class DateTime
|
||||
{
|
||||
/// <summary>
|
||||
/// The minimum <see cref="T:System.DateTime"/> value supported by the specification.
|
||||
/// </summary>
|
||||
public static readonly System.DateTime SpecMinimumDateTime = new System.DateTime(1990, 1, 1);
|
||||
|
||||
/// <summary>
|
||||
/// The maximum <see cref="T:System.DateTime"/> value supported by the specification.
|
||||
/// </summary>
|
||||
public static readonly System.DateTime SpecMaximumDateTime = new System.DateTime(2089, 12, 31, 23, 59, 59, 999);
|
||||
|
||||
/// <summary>
|
||||
/// Parses a <see cref="T:System.DateTime"/> value from bytes.
|
||||
/// </summary>
|
||||
/// <param name="bytes">Input bytes read from PLC.</param>
|
||||
/// <returns>A <see cref="T:System.DateTime"/> object representing the value read from PLC.</returns>
|
||||
/// <exception cref="ArgumentOutOfRangeException">Thrown when the length of
|
||||
/// <paramref name="bytes"/> is not 8 or any value in <paramref name="bytes"/>
|
||||
/// is outside the valid range of values.</exception>
|
||||
public static System.DateTime FromByteArray(byte[] bytes)
|
||||
{
|
||||
return FromByteArrayImpl(bytes);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parses an array of <see cref="T:System.DateTime"/> values from bytes.
|
||||
/// </summary>
|
||||
/// <param name="bytes">Input bytes read from PLC.</param>
|
||||
/// <returns>An array of <see cref="T:System.DateTime"/> objects representing the values read from PLC.</returns>
|
||||
/// <exception cref="ArgumentOutOfRangeException">Thrown when the length of
|
||||
/// <paramref name="bytes"/> is not a multiple of 8 or any value in
|
||||
/// <paramref name="bytes"/> is outside the valid range of values.</exception>
|
||||
public static System.DateTime[] ToArray(byte[] bytes)
|
||||
{
|
||||
if (bytes.Length % 8 != 0)
|
||||
throw new ArgumentOutOfRangeException(nameof(bytes), bytes.Length,
|
||||
$"Parsing an array of DateTime requires a multiple of 8 bytes of input data, input data is '{bytes.Length}' long.");
|
||||
|
||||
var cnt = bytes.Length / 8;
|
||||
var result = new System.DateTime[bytes.Length / 8];
|
||||
|
||||
for (var i = 0; i < cnt; i++)
|
||||
result[i] = FromByteArrayImpl(new ArraySegment<byte>(bytes, i * 8, 8));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static System.DateTime FromByteArrayImpl(IList<byte> bytes)
|
||||
{
|
||||
if (bytes.Count != 8)
|
||||
throw new ArgumentOutOfRangeException(nameof(bytes), bytes.Count,
|
||||
$"Parsing a DateTime requires exactly 8 bytes of input data, input data is {bytes.Count} bytes long.");
|
||||
|
||||
int DecodeBcd(byte input) => 10 * (input >> 4) + (input & 0b00001111);
|
||||
|
||||
int ByteToYear(byte bcdYear)
|
||||
{
|
||||
var input = DecodeBcd(bcdYear);
|
||||
if (input < 90) return input + 2000;
|
||||
if (input < 100) return input + 1900;
|
||||
|
||||
throw new ArgumentOutOfRangeException(nameof(bcdYear), bcdYear,
|
||||
$"Value '{input}' is higher than the maximum '99' of S7 date and time representation.");
|
||||
}
|
||||
|
||||
int AssertRangeInclusive(int input, byte min, byte max, string field)
|
||||
{
|
||||
if (input < min)
|
||||
throw new ArgumentOutOfRangeException(nameof(input), input,
|
||||
$"Value '{input}' is lower than the minimum '{min}' allowed for {field}.");
|
||||
if (input > max)
|
||||
throw new ArgumentOutOfRangeException(nameof(input), input,
|
||||
$"Value '{input}' is higher than the maximum '{max}' allowed for {field}.");
|
||||
|
||||
return input;
|
||||
}
|
||||
|
||||
var year = ByteToYear(bytes[0]);
|
||||
var month = AssertRangeInclusive(DecodeBcd(bytes[1]), 1, 12, "month");
|
||||
var day = AssertRangeInclusive(DecodeBcd(bytes[2]), 1, 31, "day of month");
|
||||
var hour = AssertRangeInclusive(DecodeBcd(bytes[3]), 0, 23, "hour");
|
||||
var minute = AssertRangeInclusive(DecodeBcd(bytes[4]), 0, 59, "minute");
|
||||
var second = AssertRangeInclusive(DecodeBcd(bytes[5]), 0, 59, "second");
|
||||
var hsec = AssertRangeInclusive(DecodeBcd(bytes[6]), 0, 99, "first two millisecond digits");
|
||||
var msec = AssertRangeInclusive(bytes[7] >> 4, 0, 9, "third millisecond digit");
|
||||
var dayOfWeek = AssertRangeInclusive(bytes[7] & 0b00001111, 1, 7, "day of week");
|
||||
|
||||
return new System.DateTime(year, month, day, hour, minute, second, hsec * 10 + msec);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts a <see cref="T:System.DateTime"/> value to a byte array.
|
||||
/// </summary>
|
||||
/// <param name="dateTime">The DateTime value to convert.</param>
|
||||
/// <returns>A byte array containing the S7 date time representation of <paramref name="dateTime"/>.</returns>
|
||||
/// <exception cref="ArgumentOutOfRangeException">Thrown when the value of
|
||||
/// <paramref name="dateTime"/> is before <see cref="P:SpecMinimumDateTime"/>
|
||||
/// or after <see cref="P:SpecMaximumDateTime"/>.</exception>
|
||||
public static byte[] ToByteArray(System.DateTime dateTime)
|
||||
{
|
||||
byte EncodeBcd(int value)
|
||||
{
|
||||
return (byte) ((value / 10 << 4) | value % 10);
|
||||
}
|
||||
|
||||
if (dateTime < SpecMinimumDateTime)
|
||||
throw new ArgumentOutOfRangeException(nameof(dateTime), dateTime,
|
||||
$"Date time '{dateTime}' is before the minimum '{SpecMinimumDateTime}' supported in S7 date time representation.");
|
||||
|
||||
if (dateTime > SpecMaximumDateTime)
|
||||
throw new ArgumentOutOfRangeException(nameof(dateTime), dateTime,
|
||||
$"Date time '{dateTime}' is after the maximum '{SpecMaximumDateTime}' supported in S7 date time representation.");
|
||||
|
||||
byte MapYear(int year) => (byte) (year < 2000 ? year - 1900 : year - 2000);
|
||||
|
||||
int DayOfWeekToInt(DayOfWeek dayOfWeek) => (int) dayOfWeek + 1;
|
||||
|
||||
return new[]
|
||||
{
|
||||
EncodeBcd(MapYear(dateTime.Year)),
|
||||
EncodeBcd(dateTime.Month),
|
||||
EncodeBcd(dateTime.Day),
|
||||
EncodeBcd(dateTime.Hour),
|
||||
EncodeBcd(dateTime.Minute),
|
||||
EncodeBcd(dateTime.Second),
|
||||
EncodeBcd(dateTime.Millisecond / 10),
|
||||
(byte) (dateTime.Millisecond % 10 << 4 | DayOfWeekToInt(dateTime.DayOfWeek))
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts an array of <see cref="T:System.DateTime"/> values to a byte array.
|
||||
/// </summary>
|
||||
/// <param name="dateTimes">The DateTime values to convert.</param>
|
||||
/// <returns>A byte array containing the S7 date time representations of <paramref name="dateTime"/>.</returns>
|
||||
/// <exception cref="ArgumentOutOfRangeException">Thrown when any value of
|
||||
/// <paramref name="dateTimes"/> is before <see cref="P:SpecMinimumDateTime"/>
|
||||
/// or after <see cref="P:SpecMaximumDateTime"/>.</exception>
|
||||
public static byte[] ToByteArray(System.DateTime[] dateTimes)
|
||||
{
|
||||
var bytes = new List<byte>(dateTimes.Length * 8);
|
||||
foreach (var dateTime in dateTimes) bytes.AddRange(ToByteArray(dateTime));
|
||||
|
||||
return bytes.ToArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
185
S7.Net/Types/DateTimeLong.cs
Normal file
185
S7.Net/Types/DateTimeLong.cs
Normal file
@@ -0,0 +1,185 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace S7.Net.Types
|
||||
{
|
||||
/// <summary>
|
||||
/// Contains the methods to convert between <see cref="T:System.DateTime" /> and S7 representation of DateTimeLong (DTL) values.
|
||||
/// </summary>
|
||||
public static class DateTimeLong
|
||||
{
|
||||
public const int TypeLengthInBytes = 12;
|
||||
/// <summary>
|
||||
/// The minimum <see cref="T:System.DateTime" /> value supported by the specification.
|
||||
/// </summary>
|
||||
public static readonly System.DateTime SpecMinimumDateTime = new System.DateTime(1970, 1, 1);
|
||||
|
||||
/// <summary>
|
||||
/// The maximum <see cref="T:System.DateTime" /> value supported by the specification.
|
||||
/// </summary>
|
||||
public static readonly System.DateTime SpecMaximumDateTime = new System.DateTime(2262, 4, 11, 23, 47, 16, 854);
|
||||
|
||||
/// <summary>
|
||||
/// Parses a <see cref="T:System.DateTime" /> value from bytes.
|
||||
/// </summary>
|
||||
/// <param name="bytes">Input bytes read from PLC.</param>
|
||||
/// <returns>A <see cref="T:System.DateTime" /> object representing the value read from PLC.</returns>
|
||||
/// <exception cref="ArgumentOutOfRangeException">
|
||||
/// Thrown when the length of
|
||||
/// <paramref name="bytes" /> is not 12 or any value in <paramref name="bytes" />
|
||||
/// is outside the valid range of values.
|
||||
/// </exception>
|
||||
public static System.DateTime FromByteArray(byte[] bytes)
|
||||
{
|
||||
return FromByteArrayImpl(bytes);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parses an array of <see cref="T:System.DateTime" /> values from bytes.
|
||||
/// </summary>
|
||||
/// <param name="bytes">Input bytes read from PLC.</param>
|
||||
/// <returns>An array of <see cref="T:System.DateTime" /> objects representing the values read from PLC.</returns>
|
||||
/// <exception cref="ArgumentOutOfRangeException">
|
||||
/// Thrown when the length of
|
||||
/// <paramref name="bytes" /> is not a multiple of 12 or any value in
|
||||
/// <paramref name="bytes" /> is outside the valid range of values.
|
||||
/// </exception>
|
||||
public static System.DateTime[] ToArray(byte[] bytes)
|
||||
{
|
||||
if (bytes.Length % TypeLengthInBytes != 0)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(bytes), bytes.Length,
|
||||
$"Parsing an array of DateTimeLong requires a multiple of 12 bytes of input data, input data is '{bytes.Length}' long.");
|
||||
}
|
||||
|
||||
var cnt = bytes.Length / TypeLengthInBytes;
|
||||
var result = new System.DateTime[cnt];
|
||||
|
||||
for (var i = 0; i < cnt; i++)
|
||||
{
|
||||
var slice = new byte[TypeLengthInBytes];
|
||||
Array.Copy(bytes, i * TypeLengthInBytes, slice, 0, TypeLengthInBytes);
|
||||
result[i] = FromByteArrayImpl(slice);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static System.DateTime FromByteArrayImpl(byte[] bytes)
|
||||
{
|
||||
if (bytes.Length != TypeLengthInBytes)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(bytes), bytes.Length,
|
||||
$"Parsing a DateTimeLong requires exactly 12 bytes of input data, input data is {bytes.Length} bytes long.");
|
||||
}
|
||||
|
||||
|
||||
var year = AssertRangeInclusive(Word.FromBytes(bytes[1], bytes[0]), 1970, 2262, "year");
|
||||
var month = AssertRangeInclusive(bytes[2], 1, 12, "month");
|
||||
var day = AssertRangeInclusive(bytes[3], 1, 31, "day of month");
|
||||
var dayOfWeek = AssertRangeInclusive(bytes[4], 1, 7, "day of week");
|
||||
var hour = AssertRangeInclusive(bytes[5], 0, 23, "hour");
|
||||
var minute = AssertRangeInclusive(bytes[6], 0, 59, "minute");
|
||||
var second = AssertRangeInclusive(bytes[7], 0, 59, "second");
|
||||
;
|
||||
|
||||
var nanoseconds = AssertRangeInclusive<uint>(DWord.FromBytes(bytes[11], bytes[10], bytes[9], bytes[8]), 0,
|
||||
999999999, "nanoseconds");
|
||||
|
||||
var time = new System.DateTime(year, month, day, hour, minute, second);
|
||||
return time.AddTicks(nanoseconds / 100);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts a <see cref="T:System.DateTime" /> value to a byte array.
|
||||
/// </summary>
|
||||
/// <param name="dateTime">The DateTime value to convert.</param>
|
||||
/// <returns>A byte array containing the S7 DateTimeLong representation of <paramref name="dateTime" />.</returns>
|
||||
/// <exception cref="ArgumentOutOfRangeException">
|
||||
/// Thrown when the value of
|
||||
/// <paramref name="dateTime" /> is before <see cref="P:SpecMinimumDateTime" />
|
||||
/// or after <see cref="P:SpecMaximumDateTime" />.
|
||||
/// </exception>
|
||||
public static byte[] ToByteArray(System.DateTime dateTime)
|
||||
{
|
||||
if (dateTime < SpecMinimumDateTime)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(dateTime), dateTime,
|
||||
$"Date time '{dateTime}' is before the minimum '{SpecMinimumDateTime}' supported in S7 DateTimeLong representation.");
|
||||
}
|
||||
|
||||
if (dateTime > SpecMaximumDateTime)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(dateTime), dateTime,
|
||||
$"Date time '{dateTime}' is after the maximum '{SpecMaximumDateTime}' supported in S7 DateTimeLong representation.");
|
||||
}
|
||||
|
||||
var stream = new MemoryStream(TypeLengthInBytes);
|
||||
// Convert Year
|
||||
stream.Write(Word.ToByteArray(Convert.ToUInt16(dateTime.Year)), 0, 2);
|
||||
|
||||
// Convert Month
|
||||
stream.WriteByte(Convert.ToByte(dateTime.Month));
|
||||
|
||||
// Convert Day
|
||||
stream.WriteByte(Convert.ToByte(dateTime.Day));
|
||||
|
||||
// Convert WeekDay. NET DateTime starts with Sunday = 0, while S7DT has Sunday = 1.
|
||||
stream.WriteByte(Convert.ToByte(dateTime.DayOfWeek + 1));
|
||||
|
||||
// Convert Hour
|
||||
stream.WriteByte(Convert.ToByte(dateTime.Hour));
|
||||
|
||||
// Convert Minutes
|
||||
stream.WriteByte(Convert.ToByte(dateTime.Minute));
|
||||
|
||||
// Convert Seconds
|
||||
stream.WriteByte(Convert.ToByte(dateTime.Second));
|
||||
|
||||
// Convert Nanoseconds. Net DateTime has a representation of 1 Tick = 100ns.
|
||||
// Thus First take the ticks Mod 1 Second (1s = 10'000'000 ticks), and then Convert to nanoseconds.
|
||||
stream.Write(DWord.ToByteArray(Convert.ToUInt32(dateTime.Ticks % 10000000 * 100)), 0, 4);
|
||||
|
||||
return stream.ToArray();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts an array of <see cref="T:System.DateTime" /> values to a byte array.
|
||||
/// </summary>
|
||||
/// <param name="dateTimes">The DateTime values to convert.</param>
|
||||
/// <returns>A byte array containing the S7 DateTimeLong representations of <paramref name="dateTimes" />.</returns>
|
||||
/// <exception cref="ArgumentOutOfRangeException">
|
||||
/// Thrown when any value of
|
||||
/// <paramref name="dateTimes" /> is before <see cref="P:SpecMinimumDateTime" />
|
||||
/// or after <see cref="P:SpecMaximumDateTime" />.
|
||||
/// </exception>
|
||||
public static byte[] ToByteArray(System.DateTime[] dateTimes)
|
||||
{
|
||||
var bytes = new List<byte>(dateTimes.Length * TypeLengthInBytes);
|
||||
foreach (var dateTime in dateTimes)
|
||||
{
|
||||
bytes.AddRange(ToByteArray(dateTime));
|
||||
}
|
||||
|
||||
return bytes.ToArray();
|
||||
}
|
||||
|
||||
private static T AssertRangeInclusive<T>(T input, T min, T max, string field) where T : IComparable<T>
|
||||
{
|
||||
if (input.CompareTo(min) < 0)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(input), input,
|
||||
$"Value '{input}' is lower than the minimum '{min}' allowed for {field}.");
|
||||
}
|
||||
|
||||
if (input.CompareTo(max) > 0)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(input), input,
|
||||
$"Value '{input}' is higher than the maximum '{max}' allowed for {field}.");
|
||||
}
|
||||
|
||||
return input;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,50 +5,13 @@ namespace S7.Net.Types
|
||||
/// <summary>
|
||||
/// Contains the conversion methods to convert Real from S7 plc to C# double.
|
||||
/// </summary>
|
||||
[Obsolete("Class Double is obsolete. Use Real instead for 32bit floating point, or LReal for 64bit floating point.")]
|
||||
public static class Double
|
||||
{
|
||||
/// <summary>
|
||||
/// Converts a S7 Real (4 bytes) to double
|
||||
/// </summary>
|
||||
public static double FromByteArray(byte[] bytes)
|
||||
{
|
||||
if (bytes.Length != 4)
|
||||
{
|
||||
throw new ArgumentException("Wrong number of bytes. Bytes array must contain 4 bytes.");
|
||||
}
|
||||
byte v1 = bytes[0];
|
||||
byte v2 = bytes[1];
|
||||
byte v3 = bytes[2];
|
||||
byte v4 = bytes[3];
|
||||
|
||||
if ((int)v1 + v2 + v3 + v4 == 0)
|
||||
{
|
||||
return 0.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
// nun String bilden
|
||||
string txt = ValToBinString(v1) + ValToBinString(v2) + ValToBinString(v3) + ValToBinString(v4);
|
||||
// erstmal das Vorzeichen
|
||||
int vz = int.Parse(txt.Substring(0, 1));
|
||||
int exd = Conversion.BinStringToInt32(txt.Substring(1, 8));
|
||||
string ma = txt.Substring(9, 23);
|
||||
double mantisse = 1;
|
||||
double faktor = 1.0;
|
||||
|
||||
//das ist die Anzahl der restlichen bit's
|
||||
for (int cnt = 0; cnt <= 22; cnt++)
|
||||
{
|
||||
faktor = faktor / 2.0;
|
||||
//entspricht 2^-y
|
||||
if (ma.Substring(cnt, 1) == "1")
|
||||
{
|
||||
mantisse = mantisse + faktor;
|
||||
}
|
||||
}
|
||||
return Math.Pow((-1), vz) * Math.Pow(2, (exd - 127)) * mantisse;
|
||||
}
|
||||
}
|
||||
public static double FromByteArray(byte[] bytes) => Real.FromByteArray(bytes);
|
||||
|
||||
/// <summary>
|
||||
/// Converts a S7 DInt to double
|
||||
@@ -74,51 +37,7 @@ namespace S7.Net.Types
|
||||
/// <summary>
|
||||
/// Converts a double to S7 Real (4 bytes)
|
||||
/// </summary>
|
||||
public static byte[] ToByteArray(double value)
|
||||
{
|
||||
double wert = (double)value;
|
||||
string binString = "";
|
||||
byte[] bytes = new byte[4];
|
||||
if (wert != 0f)
|
||||
{
|
||||
if (wert < 0)
|
||||
{
|
||||
wert *= -1;
|
||||
binString = "1";
|
||||
}
|
||||
else
|
||||
{
|
||||
binString = "0";
|
||||
}
|
||||
int exponent = (int)Math.Floor((double)Math.Log(wert) / Math.Log(2.0));
|
||||
wert = wert / (Math.Pow(2, exponent)) - 1;
|
||||
|
||||
binString += ValToBinString((byte)(exponent + 127));
|
||||
for (int cnt = 1; cnt <= 23; cnt++)
|
||||
{
|
||||
if (!(wert - System.Math.Pow(2, -cnt) < 0))
|
||||
{
|
||||
wert = wert - System.Math.Pow(2, -cnt);
|
||||
binString += "1";
|
||||
}
|
||||
else
|
||||
binString += "0";
|
||||
}
|
||||
bytes[0] = (byte)BinStringToByte(binString.Substring(0, 8));
|
||||
bytes[1] = (byte)BinStringToByte(binString.Substring(8, 8));
|
||||
bytes[2] = (byte)BinStringToByte(binString.Substring(16, 8));
|
||||
bytes[3] = (byte)BinStringToByte(binString.Substring(24, 8));
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
bytes[0] = 0;
|
||||
bytes[1] = 0;
|
||||
bytes[2] = 0;
|
||||
bytes[3] = 0;
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
public static byte[] ToByteArray(double value) => Real.ToByteArray((float)value);
|
||||
|
||||
/// <summary>
|
||||
/// Converts an array of double to an array of bytes
|
||||
@@ -128,7 +47,7 @@ namespace S7.Net.Types
|
||||
ByteArray arr = new ByteArray();
|
||||
foreach (double val in value)
|
||||
arr.Add(ToByteArray(val));
|
||||
return arr.array;
|
||||
return arr.Array;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -145,38 +64,5 @@ namespace S7.Net.Types
|
||||
return values;
|
||||
}
|
||||
|
||||
|
||||
private static string ValToBinString(byte value)
|
||||
{
|
||||
string txt = "";
|
||||
|
||||
for (int cnt = 7; cnt >= 0; cnt += -1)
|
||||
{
|
||||
if ((value & (byte)Math.Pow(2, cnt)) > 0)
|
||||
txt += "1";
|
||||
else
|
||||
txt += "0";
|
||||
}
|
||||
return txt;
|
||||
}
|
||||
|
||||
private static byte? BinStringToByte(string txt)
|
||||
{
|
||||
int cnt = 0;
|
||||
int ret = 0;
|
||||
|
||||
if (txt.Length == 8)
|
||||
{
|
||||
for (cnt = 7; cnt >= 0; cnt += -1)
|
||||
{
|
||||
if (int.Parse(txt.Substring(cnt, 1)) == 1)
|
||||
{
|
||||
ret += (int)(Math.Pow(2, (txt.Length - 1 - cnt)));
|
||||
}
|
||||
}
|
||||
return (byte)ret;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ namespace S7.Net.Types
|
||||
/// <summary>
|
||||
/// Converts a S7 Int (2 bytes) to short (Int16)
|
||||
/// </summary>
|
||||
public static Int16 FromByteArray(byte[] bytes)
|
||||
public static short FromByteArray(byte[] bytes)
|
||||
{
|
||||
if (bytes.Length != 2)
|
||||
{
|
||||
@@ -18,16 +18,9 @@ namespace S7.Net.Types
|
||||
}
|
||||
// bytes[0] -> HighByte
|
||||
// bytes[1] -> LowByte
|
||||
return FromBytes(bytes[1], bytes[0]);
|
||||
return (short)((int)(bytes[1]) | ((int)(bytes[0]) << 8));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts a S7 Int (2 bytes) to short (Int16)
|
||||
/// </summary>
|
||||
public static Int16 FromBytes(byte LoVal, byte HiVal)
|
||||
{
|
||||
return (Int16)(HiVal * 256 + LoVal);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts a short (Int16) to a S7 Int byte array (2 bytes)
|
||||
@@ -35,16 +28,10 @@ namespace S7.Net.Types
|
||||
public static byte[] ToByteArray(Int16 value)
|
||||
{
|
||||
byte[] bytes = new byte[2];
|
||||
int x = 2;
|
||||
long valLong = (long)((Int16)value);
|
||||
for (int cnt = 0; cnt < x; cnt++)
|
||||
{
|
||||
Int64 x1 = (Int64)Math.Pow(256, (cnt));
|
||||
|
||||
Int64 x3 = (Int64)(valLong / x1);
|
||||
bytes[x - cnt - 1] = (byte)(x3 & 255);
|
||||
valLong -= bytes[x - cnt - 1] * x1;
|
||||
}
|
||||
bytes[0] = (byte) (value >> 8 & 0xFF);
|
||||
bytes[1] = (byte)(value & 0xFF);
|
||||
|
||||
return bytes;
|
||||
}
|
||||
|
||||
@@ -53,10 +40,15 @@ namespace S7.Net.Types
|
||||
/// </summary>
|
||||
public static byte[] ToByteArray(Int16[] value)
|
||||
{
|
||||
ByteArray arr = new ByteArray();
|
||||
foreach (Int16 val in value)
|
||||
arr.Add(ToByteArray(val));
|
||||
return arr.array;
|
||||
byte[] bytes = new byte[value.Length * 2];
|
||||
int bytesPos = 0;
|
||||
|
||||
for(int i=0; i< value.Length; i++)
|
||||
{
|
||||
bytes[bytesPos++] = (byte)((value[i] >> 8) & 0xFF);
|
||||
bytes[bytesPos++] = (byte) (value[i] & 0xFF);
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -64,10 +56,12 @@ namespace S7.Net.Types
|
||||
/// </summary>
|
||||
public static Int16[] ToArray(byte[] bytes)
|
||||
{
|
||||
Int16[] values = new Int16[bytes.Length / 2];
|
||||
int shortsCount = bytes.Length / 2;
|
||||
|
||||
Int16[] values = new Int16[shortsCount];
|
||||
|
||||
int counter = 0;
|
||||
for (int cnt = 0; cnt < bytes.Length / 2; cnt++)
|
||||
for (int cnt = 0; cnt < shortsCount; cnt++)
|
||||
values[cnt] = FromByteArray(new byte[] { bytes[counter++], bytes[counter++] });
|
||||
|
||||
return values;
|
||||
|
||||
57
S7.Net/Types/LReal.cs
Normal file
57
S7.Net/Types/LReal.cs
Normal file
@@ -0,0 +1,57 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace S7.Net.Types
|
||||
{
|
||||
/// <summary>
|
||||
/// Contains the conversion methods to convert Real from S7 plc to C# double.
|
||||
/// </summary>
|
||||
public static class LReal
|
||||
{
|
||||
/// <summary>
|
||||
/// Converts a S7 LReal (8 bytes) to double
|
||||
/// </summary>
|
||||
public static double FromByteArray(byte[] bytes)
|
||||
{
|
||||
if (bytes.Length != 8)
|
||||
{
|
||||
throw new ArgumentException("Wrong number of bytes. Bytes array must contain 8 bytes.");
|
||||
}
|
||||
var buffer = bytes;
|
||||
|
||||
// sps uses bigending so we have to reverse if platform needs
|
||||
if (BitConverter.IsLittleEndian)
|
||||
{
|
||||
Array.Reverse(buffer);
|
||||
}
|
||||
|
||||
return BitConverter.ToDouble(buffer, 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts a double to S7 LReal (8 bytes)
|
||||
/// </summary>
|
||||
public static byte[] ToByteArray(double value)
|
||||
{
|
||||
var bytes = BitConverter.GetBytes(value);
|
||||
|
||||
// sps uses bigending so we have to check if platform is same
|
||||
if (BitConverter.IsLittleEndian)
|
||||
{
|
||||
Array.Reverse(bytes);
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts an array of double to an array of bytes
|
||||
/// </summary>
|
||||
public static byte[] ToByteArray(double[] value) => TypeHelper.ToByteArray(value, ToByteArray);
|
||||
|
||||
/// <summary>
|
||||
/// Converts an array of S7 LReal to an array of double
|
||||
/// </summary>
|
||||
public static double[] ToArray(byte[] bytes) => TypeHelper.ToArray(bytes, FromByteArray);
|
||||
|
||||
}
|
||||
}
|
||||
75
S7.Net/Types/Real.cs
Normal file
75
S7.Net/Types/Real.cs
Normal file
@@ -0,0 +1,75 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace S7.Net.Types
|
||||
{
|
||||
/// <summary>
|
||||
/// Contains the conversion methods to convert Real from S7 plc to C# double.
|
||||
/// </summary>
|
||||
public static class Real
|
||||
{
|
||||
/// <summary>
|
||||
/// Converts a S7 Real (4 bytes) to float
|
||||
/// </summary>
|
||||
public static float FromByteArray(byte[] bytes)
|
||||
{
|
||||
if (bytes.Length != 4)
|
||||
{
|
||||
throw new ArgumentException("Wrong number of bytes. Bytes array must contain 4 bytes.");
|
||||
}
|
||||
|
||||
// sps uses bigending so we have to reverse if platform needs
|
||||
if (BitConverter.IsLittleEndian)
|
||||
{
|
||||
// create deep copy of the array and reverse
|
||||
bytes = new byte[] { bytes[3], bytes[2], bytes[1], bytes[0] };
|
||||
}
|
||||
|
||||
return BitConverter.ToSingle(bytes, 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts a float to S7 Real (4 bytes)
|
||||
/// </summary>
|
||||
public static byte[] ToByteArray(float value)
|
||||
{
|
||||
byte[] bytes = BitConverter.GetBytes(value);
|
||||
|
||||
// sps uses bigending so we have to check if platform is same
|
||||
if (!BitConverter.IsLittleEndian) return bytes;
|
||||
|
||||
// create deep copy of the array and reverse
|
||||
return new byte[] { bytes[3], bytes[2], bytes[1], bytes[0] };
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts an array of float to an array of bytes
|
||||
/// </summary>
|
||||
public static byte[] ToByteArray(float[] value)
|
||||
{
|
||||
var buffer = new byte[4 * value.Length];
|
||||
var stream = new MemoryStream(buffer);
|
||||
foreach (var val in value)
|
||||
{
|
||||
stream.Write(ToByteArray(val), 0, 4);
|
||||
}
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts an array of S7 Real to an array of float
|
||||
/// </summary>
|
||||
public static float[] ToArray(byte[] bytes)
|
||||
{
|
||||
var values = new float[bytes.Length / 4];
|
||||
|
||||
int counter = 0;
|
||||
for (int cnt = 0; cnt < bytes.Length / 4; cnt++)
|
||||
values[cnt] = FromByteArray(new byte[] { bytes[counter++], bytes[counter++], bytes[counter++], bytes[counter++] });
|
||||
|
||||
return values;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
69
S7.Net/Types/S7String.cs
Normal file
69
S7.Net/Types/S7String.cs
Normal file
@@ -0,0 +1,69 @@
|
||||
using System;
|
||||
using System.Text;
|
||||
|
||||
namespace S7.Net.Types
|
||||
{
|
||||
/// <summary>
|
||||
/// Contains the methods to convert from S7 strings to C# strings
|
||||
/// An S7 String has a preceeding 2 byte header containing its capacity and length
|
||||
/// </summary>
|
||||
public static class S7String
|
||||
{
|
||||
/// <summary>
|
||||
/// Converts S7 bytes to a string
|
||||
/// </summary>
|
||||
/// <param name="bytes"></param>
|
||||
/// <returns></returns>
|
||||
public static string FromByteArray(byte[] bytes)
|
||||
{
|
||||
if (bytes.Length < 2)
|
||||
{
|
||||
throw new PlcException(ErrorCode.ReadData, "Malformed S7 String / too short");
|
||||
}
|
||||
|
||||
int size = bytes[0];
|
||||
int length = bytes[1];
|
||||
if (length > size)
|
||||
{
|
||||
throw new PlcException(ErrorCode.ReadData, "Malformed S7 String / length larger than capacity");
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
return Encoding.ASCII.GetString(bytes, 2, length);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new PlcException(ErrorCode.ReadData,
|
||||
$"Failed to parse {VarType.S7String} from data. Following fields were read: size: '{size}', actual length: '{length}', total number of bytes (including header): '{bytes.Length}'.",
|
||||
e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts a <see cref="T:string"/> to S7 string with 2-byte header.
|
||||
/// </summary>
|
||||
/// <param name="value">The string to convert to byte array.</param>
|
||||
/// <param name="reservedLength">The length (in characters) allocated in PLC for the string.</param>
|
||||
/// <returns>A <see cref="T:byte[]" /> containing the string header and string value with a maximum length of <paramref name="reservedLength"/> + 2.</returns>
|
||||
public static byte[] ToByteArray(string value, int reservedLength)
|
||||
{
|
||||
if (value is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(value));
|
||||
}
|
||||
|
||||
if (reservedLength > 254) throw new ArgumentException($"The maximum string length supported is 254.");
|
||||
|
||||
var bytes = Encoding.ASCII.GetBytes(value);
|
||||
if (bytes.Length > reservedLength) throw new ArgumentException($"The provided string length ({bytes.Length} is larger than the specified reserved length ({reservedLength}).");
|
||||
|
||||
var buffer = new byte[2 + reservedLength];
|
||||
Array.Copy(bytes, 0, buffer, 2, bytes.Length);
|
||||
buffer[0] = (byte)reservedLength;
|
||||
buffer[1] = (byte)bytes.Length;
|
||||
return buffer;
|
||||
}
|
||||
}
|
||||
}
|
||||
67
S7.Net/Types/S7StringAttribute.cs
Normal file
67
S7.Net/Types/S7StringAttribute.cs
Normal file
@@ -0,0 +1,67 @@
|
||||
using System;
|
||||
|
||||
namespace S7.Net.Types
|
||||
{
|
||||
[AttributeUsage(AttributeTargets.Field, AllowMultiple = false)]
|
||||
public sealed class S7StringAttribute : Attribute
|
||||
{
|
||||
private readonly S7StringType type;
|
||||
private readonly int reservedLength;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="S7StringAttribute"/> class.
|
||||
/// </summary>
|
||||
/// <param name="type">The string type.</param>
|
||||
/// <param name="reservedLength">Reserved length of the string in characters.</param>
|
||||
/// <exception cref="ArgumentException">Please use a valid value for the string type</exception>
|
||||
public S7StringAttribute(S7StringType type, int reservedLength)
|
||||
{
|
||||
if (!Enum.IsDefined(typeof(S7StringType), type))
|
||||
throw new ArgumentException("Please use a valid value for the string type");
|
||||
|
||||
this.type = type;
|
||||
this.reservedLength = reservedLength;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the type of the string.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The string type.
|
||||
/// </value>
|
||||
public S7StringType Type => type;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the reserved length of the string in characters.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The reserved length of the string in characters.
|
||||
/// </value>
|
||||
public int ReservedLength => reservedLength;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the reserved length in bytes.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The reserved length in bytes.
|
||||
/// </value>
|
||||
public int ReservedLengthInBytes => type == S7StringType.S7String ? reservedLength + 2 : (reservedLength * 2) + 4;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// String type.
|
||||
/// </summary>
|
||||
public enum S7StringType
|
||||
{
|
||||
/// <summary>
|
||||
/// ASCII string.
|
||||
/// </summary>
|
||||
S7String = VarType.S7String,
|
||||
|
||||
/// <summary>
|
||||
/// Unicode string.
|
||||
/// </summary>
|
||||
S7WString = VarType.S7WString
|
||||
}
|
||||
}
|
||||
72
S7.Net/Types/S7WString.cs
Normal file
72
S7.Net/Types/S7WString.cs
Normal file
@@ -0,0 +1,72 @@
|
||||
using System;
|
||||
using System.Text;
|
||||
|
||||
namespace S7.Net.Types
|
||||
{
|
||||
/// <summary>
|
||||
/// Contains the methods to convert from S7 wstrings to C# strings
|
||||
/// An S7 WString has a preceding 4 byte header containing its capacity and length
|
||||
/// </summary>
|
||||
public static class S7WString
|
||||
{
|
||||
/// <summary>
|
||||
/// Converts S7 bytes to a string
|
||||
/// </summary>
|
||||
/// <param name="bytes"></param>
|
||||
/// <returns></returns>
|
||||
public static string FromByteArray(byte[] bytes)
|
||||
{
|
||||
if (bytes.Length < 4)
|
||||
{
|
||||
throw new PlcException(ErrorCode.ReadData, "Malformed S7 WString / too short");
|
||||
}
|
||||
|
||||
int size = (bytes[0] << 8) | bytes[1];
|
||||
int length = (bytes[2] << 8) | bytes[3];
|
||||
|
||||
if (length > size)
|
||||
{
|
||||
throw new PlcException(ErrorCode.ReadData, "Malformed S7 WString / length larger than capacity");
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
return Encoding.BigEndianUnicode.GetString(bytes, 4, length * 2);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new PlcException(ErrorCode.ReadData,
|
||||
$"Failed to parse {VarType.S7WString} from data. Following fields were read: size: '{size}', actual length: '{length}', total number of bytes (including header): '{bytes.Length}'.",
|
||||
e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts a <see cref="T:string"/> to S7 wstring with 4-byte header.
|
||||
/// </summary>
|
||||
/// <param name="value">The string to convert to byte array.</param>
|
||||
/// <param name="reservedLength">The length (in characters) allocated in PLC for the string.</param>
|
||||
/// <returns>A <see cref="T:byte[]" /> containing the string header and string value with a maximum length of <paramref name="reservedLength"/> + 4.</returns>
|
||||
public static byte[] ToByteArray(string value, int reservedLength)
|
||||
{
|
||||
if (value is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(value));
|
||||
}
|
||||
|
||||
if (reservedLength > 16382) throw new ArgumentException("The maximum string length supported is 16382.");
|
||||
|
||||
var buffer = new byte[4 + reservedLength * 2];
|
||||
buffer[0] = (byte)((reservedLength >> 8) & 0xFF);
|
||||
buffer[1] = (byte)(reservedLength & 0xFF);
|
||||
buffer[2] = (byte)((value.Length >> 8) & 0xFF);
|
||||
buffer[3] = (byte)(value.Length & 0xFF);
|
||||
|
||||
var stringLength = Encoding.BigEndianUnicode.GetBytes(value, 0, value.Length, buffer, 4) / 2;
|
||||
if (stringLength > reservedLength) throw new ArgumentException($"The provided string length ({stringLength} is larger than the specified reserved length ({reservedLength}).");
|
||||
|
||||
return buffer;
|
||||
}
|
||||
}
|
||||
}
|
||||
68
S7.Net/Types/Single.cs
Normal file
68
S7.Net/Types/Single.cs
Normal file
@@ -0,0 +1,68 @@
|
||||
using System;
|
||||
|
||||
namespace S7.Net.Types
|
||||
{
|
||||
/// <summary>
|
||||
/// Contains the conversion methods to convert Real from S7 plc to C# float.
|
||||
/// </summary>
|
||||
[Obsolete("Class Single is obsolete. Use Real instead.")]
|
||||
public static class Single
|
||||
{
|
||||
/// <summary>
|
||||
/// Converts a S7 Real (4 bytes) to float
|
||||
/// </summary>
|
||||
public static float FromByteArray(byte[] bytes) => Real.FromByteArray(bytes);
|
||||
|
||||
/// <summary>
|
||||
/// Converts a S7 DInt to float
|
||||
/// </summary>
|
||||
public static float FromDWord(Int32 value)
|
||||
{
|
||||
byte[] b = DInt.ToByteArray(value);
|
||||
float d = FromByteArray(b);
|
||||
return d;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts a S7 DWord to float
|
||||
/// </summary>
|
||||
public static float FromDWord(UInt32 value)
|
||||
{
|
||||
byte[] b = DWord.ToByteArray(value);
|
||||
float d = FromByteArray(b);
|
||||
return d;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Converts a double to S7 Real (4 bytes)
|
||||
/// </summary>
|
||||
public static byte[] ToByteArray(float value) => Real.ToByteArray(value);
|
||||
|
||||
/// <summary>
|
||||
/// Converts an array of float to an array of bytes
|
||||
/// </summary>
|
||||
public static byte[] ToByteArray(float[] value)
|
||||
{
|
||||
ByteArray arr = new ByteArray();
|
||||
foreach (float val in value)
|
||||
arr.Add(ToByteArray(val));
|
||||
return arr.Array;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts an array of S7 Real to an array of float
|
||||
/// </summary>
|
||||
public static float[] ToArray(byte[] bytes)
|
||||
{
|
||||
float[] values = new float[bytes.Length / 4];
|
||||
|
||||
int counter = 0;
|
||||
for (int cnt = 0; cnt < bytes.Length / 4; cnt++)
|
||||
values[cnt] = FromByteArray(new byte[] { bytes[counter++], bytes[counter++], bytes[counter++], bytes[counter++] });
|
||||
|
||||
return values;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,20 +1,25 @@
|
||||
namespace S7.Net.Types
|
||||
{
|
||||
/// <summary>
|
||||
/// Contains the methods to convert from S7 strings to C# strings
|
||||
/// Contains the methods to convert from S7 Array of Chars (like a const char[N] C-String) to C# strings
|
||||
/// </summary>
|
||||
public static class String
|
||||
public class String
|
||||
{
|
||||
/// <summary>
|
||||
/// Converts a string to S7 bytes
|
||||
/// Converts a string to <paramref name="reservedLength"/> of bytes, padded with 0-bytes if required.
|
||||
/// </summary>
|
||||
public static byte[] ToByteArray(string value)
|
||||
/// <param name="value">The string to write to the PLC.</param>
|
||||
/// <param name="reservedLength">The amount of bytes reserved for the <paramref name="value"/> in the PLC.</param>
|
||||
public static byte[] ToByteArray(string value, int reservedLength)
|
||||
{
|
||||
string txt = (string)value;
|
||||
char[] ca = txt.ToCharArray();
|
||||
byte[] bytes = new byte[txt.Length];
|
||||
for (int cnt = 0; cnt <= ca.Length - 1; cnt++)
|
||||
bytes[cnt] = (byte)Asc(ca[cnt].ToString());
|
||||
var length = value?.Length;
|
||||
if (length > reservedLength) length = reservedLength;
|
||||
var bytes = new byte[reservedLength];
|
||||
|
||||
if (length == null || length == 0) return bytes;
|
||||
|
||||
System.Text.Encoding.ASCII.GetBytes(value, 0, length.Value, bytes, 0);
|
||||
|
||||
return bytes;
|
||||
}
|
||||
|
||||
@@ -27,13 +32,6 @@
|
||||
{
|
||||
return System.Text.Encoding.ASCII.GetString(bytes);
|
||||
}
|
||||
|
||||
private static int Asc(string s)
|
||||
{
|
||||
byte[] b = System.Text.Encoding.ASCII.GetBytes(s);
|
||||
if (b.Length > 0)
|
||||
return b[0];
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
15
S7.Net/Types/StringEx.cs
Normal file
15
S7.Net/Types/StringEx.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
using System;
|
||||
|
||||
namespace S7.Net.Types
|
||||
{
|
||||
/// <inheritdoc cref="S7String"/>
|
||||
[Obsolete("Please use S7String class")]
|
||||
public static class StringEx
|
||||
{
|
||||
/// <inheritdoc cref="S7String.FromByteArray(byte[])"/>
|
||||
public static string FromByteArray(byte[] bytes) => S7String.FromByteArray(bytes);
|
||||
|
||||
/// <inheritdoc cref="S7String.ToByteArray(string, int)"/>
|
||||
public static byte[] ToByteArray(string value, int reservedLength) => S7String.ToByteArray(value, reservedLength);
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,5 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Globalization;
|
||||
using System.Reflection;
|
||||
|
||||
namespace S7.Net.Types
|
||||
@@ -19,8 +18,14 @@ namespace S7.Net.Types
|
||||
{
|
||||
double numBytes = 0.0;
|
||||
|
||||
System.Reflection.FieldInfo[] infos = structType.GetFields();
|
||||
foreach (System.Reflection.FieldInfo info in infos)
|
||||
var infos = structType
|
||||
#if NETSTANDARD1_3
|
||||
.GetTypeInfo().DeclaredFields;
|
||||
#else
|
||||
.GetFields();
|
||||
#endif
|
||||
|
||||
foreach (var info in infos)
|
||||
{
|
||||
switch (info.FieldType.Name)
|
||||
{
|
||||
@@ -45,13 +50,28 @@ namespace S7.Net.Types
|
||||
numBytes++;
|
||||
numBytes += 4;
|
||||
break;
|
||||
case "Float":
|
||||
case "Double":
|
||||
case "Single":
|
||||
numBytes = Math.Ceiling(numBytes);
|
||||
if ((numBytes / 2 - Math.Floor(numBytes / 2.0)) > 0)
|
||||
numBytes++;
|
||||
numBytes += 4;
|
||||
break;
|
||||
case "Double":
|
||||
numBytes = Math.Ceiling(numBytes);
|
||||
if ((numBytes / 2 - Math.Floor(numBytes / 2.0)) > 0)
|
||||
numBytes++;
|
||||
numBytes += 8;
|
||||
break;
|
||||
case "String":
|
||||
S7StringAttribute? attribute = info.GetCustomAttributes<S7StringAttribute>().SingleOrDefault();
|
||||
if (attribute == default(S7StringAttribute))
|
||||
throw new ArgumentException("Please add S7StringAttribute to the string field");
|
||||
|
||||
numBytes = Math.Ceiling(numBytes);
|
||||
if ((numBytes / 2 - Math.Floor(numBytes / 2.0)) > 0)
|
||||
numBytes++;
|
||||
numBytes += attribute.ReservedLengthInBytes;
|
||||
break;
|
||||
default:
|
||||
numBytes += GetStructSize(info.FieldType);
|
||||
break;
|
||||
@@ -66,7 +86,7 @@ namespace S7.Net.Types
|
||||
/// <param name="structType">The struct type</param>
|
||||
/// <param name="bytes">The array of bytes</param>
|
||||
/// <returns>The object depending on the struct type or null if fails(array-length != struct-length</returns>
|
||||
public static object FromBytes(Type structType, byte[] bytes)
|
||||
public static object? FromBytes(Type structType, byte[] bytes)
|
||||
{
|
||||
if (bytes == null)
|
||||
return null;
|
||||
@@ -80,8 +100,15 @@ namespace S7.Net.Types
|
||||
double numBytes = 0.0;
|
||||
object structValue = Activator.CreateInstance(structType);
|
||||
|
||||
System.Reflection.FieldInfo[] infos = structValue.GetType().GetFields();
|
||||
foreach (System.Reflection.FieldInfo info in infos)
|
||||
|
||||
var infos = structValue.GetType()
|
||||
#if NETSTANDARD1_3
|
||||
.GetTypeInfo().DeclaredFields;
|
||||
#else
|
||||
.GetFields();
|
||||
#endif
|
||||
|
||||
foreach (var info in infos)
|
||||
{
|
||||
switch (info.FieldType.Name)
|
||||
{
|
||||
@@ -104,7 +131,7 @@ namespace S7.Net.Types
|
||||
numBytes = Math.Ceiling(numBytes);
|
||||
if ((numBytes / 2 - Math.Floor(numBytes / 2.0)) > 0)
|
||||
numBytes++;
|
||||
// hier auswerten
|
||||
// get the value
|
||||
ushort source = Word.FromBytes(bytes[(int)numBytes + 1], bytes[(int)numBytes]);
|
||||
info.SetValue(structValue, source.ConvertToShort());
|
||||
numBytes += 2;
|
||||
@@ -113,7 +140,7 @@ namespace S7.Net.Types
|
||||
numBytes = Math.Ceiling(numBytes);
|
||||
if ((numBytes / 2 - Math.Floor(numBytes / 2.0)) > 0)
|
||||
numBytes++;
|
||||
// hier auswerten
|
||||
// get the value
|
||||
info.SetValue(structValue, Word.FromBytes(bytes[(int)numBytes + 1],
|
||||
bytes[(int)numBytes]));
|
||||
numBytes += 2;
|
||||
@@ -122,36 +149,72 @@ namespace S7.Net.Types
|
||||
numBytes = Math.Ceiling(numBytes);
|
||||
if ((numBytes / 2 - Math.Floor(numBytes / 2.0)) > 0)
|
||||
numBytes++;
|
||||
// hier auswerten
|
||||
// get the value
|
||||
uint sourceUInt = DWord.FromBytes(bytes[(int)numBytes + 3],
|
||||
bytes[(int)numBytes + 2],
|
||||
bytes[(int)numBytes + 1],
|
||||
bytes[(int)numBytes + 0]);
|
||||
info.SetValue(structValue, sourceUInt.ConvertToInt());
|
||||
bytes[(int)numBytes + 0]);
|
||||
info.SetValue(structValue, sourceUInt.ConvertToInt());
|
||||
numBytes += 4;
|
||||
break;
|
||||
case "UInt32":
|
||||
numBytes = Math.Ceiling(numBytes);
|
||||
if ((numBytes / 2 - Math.Floor(numBytes / 2.0)) > 0)
|
||||
numBytes++;
|
||||
// hier auswerten
|
||||
// get the value
|
||||
info.SetValue(structValue, DWord.FromBytes(bytes[(int)numBytes],
|
||||
bytes[(int)numBytes + 1],
|
||||
bytes[(int)numBytes + 2],
|
||||
bytes[(int)numBytes + 3]));
|
||||
numBytes += 4;
|
||||
break;
|
||||
case "Double":
|
||||
case "Single":
|
||||
numBytes = Math.Ceiling(numBytes);
|
||||
if ((numBytes / 2 - Math.Floor(numBytes / 2.0)) > 0)
|
||||
numBytes++;
|
||||
// hier auswerten
|
||||
info.SetValue(structValue, Double.FromByteArray(new byte[] { bytes[(int)numBytes],
|
||||
// get the value
|
||||
info.SetValue(structValue, Real.FromByteArray(new byte[] { bytes[(int)numBytes],
|
||||
bytes[(int)numBytes + 1],
|
||||
bytes[(int)numBytes + 2],
|
||||
bytes[(int)numBytes + 3] }));
|
||||
numBytes += 4;
|
||||
break;
|
||||
case "Double":
|
||||
numBytes = Math.Ceiling(numBytes);
|
||||
if ((numBytes / 2 - Math.Floor(numBytes / 2.0)) > 0)
|
||||
numBytes++;
|
||||
// get the value
|
||||
var data = new byte[8];
|
||||
Array.Copy(bytes, (int)numBytes, data, 0, 8);
|
||||
info.SetValue(structValue, LReal.FromByteArray(data));
|
||||
numBytes += 8;
|
||||
break;
|
||||
case "String":
|
||||
S7StringAttribute? attribute = info.GetCustomAttributes<S7StringAttribute>().SingleOrDefault();
|
||||
if (attribute == default(S7StringAttribute))
|
||||
throw new ArgumentException("Please add S7StringAttribute to the string field");
|
||||
|
||||
numBytes = Math.Ceiling(numBytes);
|
||||
if ((numBytes / 2 - Math.Floor(numBytes / 2.0)) > 0)
|
||||
numBytes++;
|
||||
|
||||
// get the value
|
||||
var sData = new byte[attribute.ReservedLengthInBytes];
|
||||
Array.Copy(bytes, (int)numBytes, sData, 0, sData.Length);
|
||||
switch (attribute.Type)
|
||||
{
|
||||
case S7StringType.S7String:
|
||||
info.SetValue(structValue, S7String.FromByteArray(sData));
|
||||
break;
|
||||
case S7StringType.S7WString:
|
||||
info.SetValue(structValue, S7WString.FromByteArray(sData));
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentException("Please use a valid string type for the S7StringAttribute");
|
||||
}
|
||||
|
||||
numBytes += sData.Length;
|
||||
break;
|
||||
default:
|
||||
var buffer = new byte[GetStructSize(info.FieldType)];
|
||||
if (buffer.Length == 0)
|
||||
@@ -176,14 +239,20 @@ namespace S7.Net.Types
|
||||
|
||||
int size = Struct.GetStructSize(type);
|
||||
byte[] bytes = new byte[size];
|
||||
byte[] bytes2 = null;
|
||||
byte[]? bytes2 = null;
|
||||
|
||||
int bytePos = 0;
|
||||
int bitPos = 0;
|
||||
double numBytes = 0.0;
|
||||
|
||||
System.Reflection.FieldInfo[] infos = type.GetFields();
|
||||
foreach (System.Reflection.FieldInfo info in infos)
|
||||
var infos = type
|
||||
#if NETSTANDARD1_3
|
||||
.GetTypeInfo().DeclaredFields;
|
||||
#else
|
||||
.GetFields();
|
||||
#endif
|
||||
|
||||
foreach (var info in infos)
|
||||
{
|
||||
bytes2 = null;
|
||||
switch (info.FieldType.Name)
|
||||
@@ -216,8 +285,23 @@ namespace S7.Net.Types
|
||||
case "UInt32":
|
||||
bytes2 = DWord.ToByteArray((UInt32)info.GetValue(structValue));
|
||||
break;
|
||||
case "Single":
|
||||
bytes2 = Real.ToByteArray((float)info.GetValue(structValue));
|
||||
break;
|
||||
case "Double":
|
||||
bytes2 = Double.ToByteArray((double)info.GetValue(structValue));
|
||||
bytes2 = LReal.ToByteArray((double)info.GetValue(structValue));
|
||||
break;
|
||||
case "String":
|
||||
S7StringAttribute? attribute = info.GetCustomAttributes<S7StringAttribute>().SingleOrDefault();
|
||||
if (attribute == default(S7StringAttribute))
|
||||
throw new ArgumentException("Please add S7StringAttribute to the string field");
|
||||
|
||||
bytes2 = attribute.Type switch
|
||||
{
|
||||
S7StringType.S7String => S7String.ToByteArray((string)info.GetValue(structValue), attribute.ReservedLength),
|
||||
S7StringType.S7WString => S7WString.ToByteArray((string)info.GetValue(structValue), attribute.ReservedLength),
|
||||
_ => throw new ArgumentException("Please use a valid string type for the S7StringAttribute")
|
||||
};
|
||||
break;
|
||||
}
|
||||
if (bytes2 != null)
|
||||
@@ -227,14 +311,12 @@ namespace S7.Net.Types
|
||||
if ((numBytes / 2 - Math.Floor(numBytes / 2.0)) > 0)
|
||||
numBytes++;
|
||||
bytePos = (int)numBytes;
|
||||
for (int bCnt=0; bCnt<bytes2.Length; bCnt++)
|
||||
for (int bCnt = 0; bCnt < bytes2.Length; bCnt++)
|
||||
bytes[bytePos + bCnt] = bytes2[bCnt];
|
||||
numBytes += bytes2.Length;
|
||||
}
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,26 +13,30 @@ namespace S7.Net.Types
|
||||
public static double FromByteArray(byte[] bytes)
|
||||
{
|
||||
double wert = 0;
|
||||
Int16 value = (Int16)Types.Word.FromBytes(bytes[1], bytes[0]);
|
||||
string txt = Conversion.ValToBinString(value);
|
||||
wert = Conversion.BinStringToInt32(txt.Substring(4, 4)) * 100.0;
|
||||
wert += Conversion.BinStringToInt32(txt.Substring(8, 4)) * 10.0;
|
||||
wert += Conversion.BinStringToInt32(txt.Substring(12, 4));
|
||||
switch (txt.Substring(2, 2))
|
||||
|
||||
wert = ((bytes[0]) & 0x0F) * 100.0;
|
||||
wert += ((bytes[1] >> 4) & 0x0F) * 10.0;
|
||||
wert += ((bytes[1]) & 0x0F) * 1.0;
|
||||
|
||||
// this value is not used... may for a nother exponation
|
||||
//int unknown = (bytes[0] >> 6) & 0x03;
|
||||
|
||||
switch ((bytes[0] >> 4) & 0x03)
|
||||
{
|
||||
case "00":
|
||||
case 0:
|
||||
wert *= 0.01;
|
||||
break;
|
||||
case "01":
|
||||
case 1:
|
||||
wert *= 0.1;
|
||||
break;
|
||||
case "10":
|
||||
case 2:
|
||||
wert *= 1.0;
|
||||
break;
|
||||
case "11":
|
||||
case 3:
|
||||
wert *= 10.0;
|
||||
break;
|
||||
}
|
||||
|
||||
return wert;
|
||||
}
|
||||
|
||||
@@ -42,16 +46,9 @@ namespace S7.Net.Types
|
||||
public static byte[] ToByteArray(UInt16 value)
|
||||
{
|
||||
byte[] bytes = new byte[2];
|
||||
int x = 2;
|
||||
long valLong = (long)((UInt16)value);
|
||||
for (int cnt = 0; cnt < x; cnt++)
|
||||
{
|
||||
Int64 x1 = (Int64)Math.Pow(256, (cnt));
|
||||
bytes[1] = (byte)((int)value & 0xFF);
|
||||
bytes[0] = (byte)((int)value >> 8 & 0xFF);
|
||||
|
||||
Int64 x3 = (Int64)(valLong / x1);
|
||||
bytes[x - cnt - 1] = (byte)(x3 & 255);
|
||||
valLong -= bytes[x - cnt - 1] * x1;
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
|
||||
@@ -63,7 +60,7 @@ namespace S7.Net.Types
|
||||
ByteArray arr = new ByteArray();
|
||||
foreach (UInt16 val in value)
|
||||
arr.Add(ToByteArray(val));
|
||||
return arr.array;
|
||||
return arr.Array;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
43
S7.Net/Types/TypeHelper.cs
Normal file
43
S7.Net/Types/TypeHelper.cs
Normal file
@@ -0,0 +1,43 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace S7.Net.Types
|
||||
{
|
||||
internal static class TypeHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// Converts an array of T to an array of bytes
|
||||
/// </summary>
|
||||
public static byte[] ToByteArray<T>(T[] value, Func<T, byte[]> converter) where T : struct
|
||||
{
|
||||
var buffer = new byte[Marshal.SizeOf(default(T)) * value.Length];
|
||||
var stream = new MemoryStream(buffer);
|
||||
foreach (var val in value)
|
||||
{
|
||||
stream.Write(converter(val), 0, 4);
|
||||
}
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts an array of T repesented as S7 binary data to an array of T
|
||||
/// </summary>
|
||||
public static T[] ToArray<T>(byte[] bytes, Func<byte[], T> converter) where T : struct
|
||||
{
|
||||
var typeSize = Marshal.SizeOf(default(T));
|
||||
var entries = bytes.Length / typeSize;
|
||||
var values = new T[entries];
|
||||
|
||||
for(int i = 0; i < entries; ++i)
|
||||
{
|
||||
var buffer = new byte[typeSize];
|
||||
Array.Copy(bytes, i * typeSize, buffer, 0, typeSize);
|
||||
values[i] = converter(buffer);
|
||||
}
|
||||
|
||||
return values;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -16,35 +16,30 @@ namespace S7.Net.Types
|
||||
{
|
||||
throw new ArgumentException("Wrong number of bytes. Bytes array must contain 2 bytes.");
|
||||
}
|
||||
// bytes[0] -> HighByte
|
||||
// bytes[1] -> LowByte
|
||||
return FromBytes(bytes[1], bytes[0]);
|
||||
|
||||
return (UInt16)((bytes[0] << 8) | bytes[1]);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Converts a word (2 bytes) to ushort (UInt16)
|
||||
/// Converts 2 bytes to ushort (UInt16)
|
||||
/// </summary>
|
||||
public static UInt16 FromBytes(byte LoVal, byte HiVal)
|
||||
public static UInt16 FromBytes(byte b1, byte b2)
|
||||
{
|
||||
return (UInt16) (HiVal*256 + LoVal);
|
||||
return (UInt16)((b2 << 8) | b1);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Converts a ushort (UInt16) to word (2 bytes)
|
||||
/// </summary>
|
||||
public static byte[] ToByteArray(UInt16 value)
|
||||
{
|
||||
byte[] bytes = new byte[2];
|
||||
int x = 2;
|
||||
long valLong = (long) ((UInt16) value);
|
||||
for (int cnt = 0; cnt < x; cnt++)
|
||||
{
|
||||
Int64 x1 = (Int64) Math.Pow(256, (cnt));
|
||||
|
||||
Int64 x3 = (Int64) (valLong/x1);
|
||||
bytes[x - cnt - 1] = (byte) (x3 & 255);
|
||||
valLong -= bytes[x - cnt - 1]*x1;
|
||||
}
|
||||
bytes[1] = (byte)(value & 0xFF);
|
||||
bytes[0] = (byte)((value>>8) & 0xFF);
|
||||
|
||||
return bytes;
|
||||
}
|
||||
|
||||
@@ -56,7 +51,7 @@ namespace S7.Net.Types
|
||||
ByteArray arr = new ByteArray();
|
||||
foreach (UInt16 val in value)
|
||||
arr.Add(ToByteArray(val));
|
||||
return arr.array;
|
||||
return arr.Array;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -1,45 +0,0 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 14
|
||||
VisualStudioVersion = 14.0.24720.0
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{7A8252C3-E6AE-435A-809D-4413C06E0711}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
README.md = README.md
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "S7.Net.Core", "S7.Net.Core\S7.Net.Core.csproj", "{CBFF80E8-3D3D-4656-A27C-A65EA5774536}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Debug|ARM = Debug|ARM
|
||||
Debug|x64 = Debug|x64
|
||||
Debug|x86 = Debug|x86
|
||||
Release|Any CPU = Release|Any CPU
|
||||
Release|ARM = Release|ARM
|
||||
Release|x64 = Release|x64
|
||||
Release|x86 = Release|x86
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{CBFF80E8-3D3D-4656-A27C-A65EA5774536}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{CBFF80E8-3D3D-4656-A27C-A65EA5774536}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{CBFF80E8-3D3D-4656-A27C-A65EA5774536}.Debug|ARM.ActiveCfg = Debug|ARM
|
||||
{CBFF80E8-3D3D-4656-A27C-A65EA5774536}.Debug|ARM.Build.0 = Debug|ARM
|
||||
{CBFF80E8-3D3D-4656-A27C-A65EA5774536}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{CBFF80E8-3D3D-4656-A27C-A65EA5774536}.Debug|x64.Build.0 = Debug|x64
|
||||
{CBFF80E8-3D3D-4656-A27C-A65EA5774536}.Debug|x86.ActiveCfg = Debug|x86
|
||||
{CBFF80E8-3D3D-4656-A27C-A65EA5774536}.Debug|x86.Build.0 = Debug|x86
|
||||
{CBFF80E8-3D3D-4656-A27C-A65EA5774536}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{CBFF80E8-3D3D-4656-A27C-A65EA5774536}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{CBFF80E8-3D3D-4656-A27C-A65EA5774536}.Release|ARM.ActiveCfg = Release|ARM
|
||||
{CBFF80E8-3D3D-4656-A27C-A65EA5774536}.Release|ARM.Build.0 = Release|ARM
|
||||
{CBFF80E8-3D3D-4656-A27C-A65EA5774536}.Release|x64.ActiveCfg = Release|x64
|
||||
{CBFF80E8-3D3D-4656-A27C-A65EA5774536}.Release|x64.Build.0 = Release|x64
|
||||
{CBFF80E8-3D3D-4656-A27C-A65EA5774536}.Release|x86.ActiveCfg = Release|x86
|
||||
{CBFF80E8-3D3D-4656-A27C-A65EA5774536}.Release|x86.Build.0 = Release|x86
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
12
S7.sln
12
S7.sln
@@ -1,14 +1,17 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 2012
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "S7.Net", "S7.Net\S7.Net.csproj", "{BFD484F9-3F04-42A2-BF2A-60A189A25DCF}"
|
||||
# Visual Studio Version 16
|
||||
VisualStudioVersion = 16.0.29806.167
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "S7.Net", "S7.Net\S7.Net.csproj", "{BFD484F9-3F04-42A2-BF2A-60A189A25DCF}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{7A8252C3-E6AE-435A-809D-4413C06E0711}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
appveyor.yml = appveyor.yml
|
||||
README.md = README.md
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "S7.Net.UnitTest", "S7.Net.UnitTest\S7.Net.UnitTest.csproj", "{303CCED6-9ABC-4899-A509-743341AAA804}"
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "S7.Net.UnitTest", "S7.Net.UnitTest\S7.Net.UnitTest.csproj", "{303CCED6-9ABC-4899-A509-743341AAA804}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
@@ -28,4 +31,7 @@ Global
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {F33D8F72-56A0-47E4-B37A-497E01977AD4}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
|
||||
13
appveyor.yml
Normal file
13
appveyor.yml
Normal file
@@ -0,0 +1,13 @@
|
||||
image: Visual Studio 2019
|
||||
configuration: Release
|
||||
install:
|
||||
- choco install gitversion.portable -y
|
||||
before_build:
|
||||
- cmd: gitversion /l console /output buildserver
|
||||
- dotnet restore
|
||||
build_script:
|
||||
msbuild /nologo /v:m /p:AssemblyVersion=%GitVersion_AssemblySemVer% /p:FileVersion=%GitVersion_MajorMinorPatch% /p:InformationalVersion=%GitVersion_InformationalVersion% /p:Configuration=%CONFIGURATION% S7.sln
|
||||
after_build:
|
||||
- dotnet pack S7.Net -c %CONFIGURATION% /p:Version=%GitVersion_NuGetVersion% --no-build -o artifacts
|
||||
artifacts:
|
||||
- path: artifacts\*.*
|
||||
1
nuget-pack/.gitignore
vendored
1
nuget-pack/.gitignore
vendored
@@ -1 +0,0 @@
|
||||
+lib/
|
||||
@@ -1,17 +0,0 @@
|
||||
<?xml version="1.0"?>
|
||||
<package>
|
||||
<metadata>
|
||||
<id>S7netplus</id>
|
||||
<version>$version$</version>
|
||||
<title>S7.Net Plus</title>
|
||||
<authors>Derek Heiser</authors>
|
||||
<owners>Derek Heiser</owners>
|
||||
<projectUrl>https://github.com/killnine/s7netplus</projectUrl>
|
||||
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
||||
<description>A continuation of Juergen1969's Siemens communication library.</description>
|
||||
<tags>PLC Siemens Communication S7</tags>
|
||||
<language>en-US</language>
|
||||
<copyright>Derek Heiser 2015</copyright>
|
||||
<dependencies></dependencies>
|
||||
</metadata>
|
||||
</package>
|
||||
Binary file not shown.
@@ -1,917 +0,0 @@
|
||||
<?xml version="1.0"?>
|
||||
<doc>
|
||||
<assembly>
|
||||
<name>S7.Net</name>
|
||||
</assembly>
|
||||
<members>
|
||||
<member name="T:S7.Net.Conversion">
|
||||
<summary>
|
||||
Conversion methods to convert from Siemens numeric format to C# and back
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:S7.Net.Conversion.BinStringToInt32(System.String)">
|
||||
<summary>
|
||||
Converts a binary string to Int32 value
|
||||
</summary>
|
||||
<param name="txt"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:S7.Net.Conversion.BinStringToByte(System.String)">
|
||||
<summary>
|
||||
Converts a binary string to a byte. Can return null.
|
||||
</summary>
|
||||
<param name="txt"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:S7.Net.Conversion.ValToBinString(System.Object)">
|
||||
<summary>
|
||||
Converts the value to a binary string
|
||||
</summary>
|
||||
<param name="value"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:S7.Net.Conversion.SelectBit(System.Byte,System.Int32)">
|
||||
<summary>
|
||||
Helper to get a bit value given a byte and the bit index.
|
||||
Example: DB1.DBX0.5 -> var bytes = ReadBytes(DB1.DBW0); bool bit = bytes[0].SelectBit(5);
|
||||
</summary>
|
||||
<param name="data"></param>
|
||||
<param name="bitPosition"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:S7.Net.Conversion.ConvertToShort(System.UInt16)">
|
||||
<summary>
|
||||
Converts from ushort value to short value; it's used to retrieve negative values from words
|
||||
</summary>
|
||||
<param name="input"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:S7.Net.Conversion.ConvertToUshort(System.Int16)">
|
||||
<summary>
|
||||
Converts from short value to ushort value; it's used to pass negative values to DWs
|
||||
</summary>
|
||||
<param name="input"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:S7.Net.Conversion.ConvertToInt(System.UInt32)">
|
||||
<summary>
|
||||
Converts from UInt32 value to Int32 value; it's used to retrieve negative values from DBDs
|
||||
</summary>
|
||||
<param name="input"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:S7.Net.Conversion.ConvertToUInt(System.Int32)">
|
||||
<summary>
|
||||
Converts from Int32 value to UInt32 value; it's used to pass negative values to DBDs
|
||||
</summary>
|
||||
<param name="input"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:S7.Net.Conversion.ConvertToUInt(System.Double)">
|
||||
<summary>
|
||||
Converts from double to DWord (DBD)
|
||||
</summary>
|
||||
<param name="input"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:S7.Net.Conversion.ConvertToDouble(System.UInt32)">
|
||||
<summary>
|
||||
Converts from DWord (DBD) to double
|
||||
</summary>
|
||||
<param name="input"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="T:S7.Net.CpuType">
|
||||
<summary>
|
||||
Types of S7 cpu supported by the library
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:S7.Net.CpuType.S7200">
|
||||
<summary>
|
||||
S7 200 cpu type
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:S7.Net.CpuType.S7300">
|
||||
<summary>
|
||||
S7 300 cpu type
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:S7.Net.CpuType.S7400">
|
||||
<summary>
|
||||
S7 400 cpu type
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:S7.Net.CpuType.S71200">
|
||||
<summary>
|
||||
S7 1200 cpu type
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:S7.Net.CpuType.S71500">
|
||||
<summary>
|
||||
S7 1500 cpu type
|
||||
</summary>
|
||||
</member>
|
||||
<member name="T:S7.Net.ErrorCode">
|
||||
<summary>
|
||||
Types of error code that can be set after a function is called
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:S7.Net.ErrorCode.NoError">
|
||||
<summary>
|
||||
The function has been executed correctly
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:S7.Net.ErrorCode.WrongCPU_Type">
|
||||
<summary>
|
||||
Wrong type of CPU error
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:S7.Net.ErrorCode.ConnectionError">
|
||||
<summary>
|
||||
Connection error
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:S7.Net.ErrorCode.IPAddressNotAvailable">
|
||||
<summary>
|
||||
Ip address not available
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:S7.Net.ErrorCode.WrongVarFormat">
|
||||
<summary>
|
||||
Wrong format of the variable
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:S7.Net.ErrorCode.WrongNumberReceivedBytes">
|
||||
<summary>
|
||||
Wrong number of received bytes
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:S7.Net.ErrorCode.SendData">
|
||||
<summary>
|
||||
Error on send data
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:S7.Net.ErrorCode.ReadData">
|
||||
<summary>
|
||||
Error on read data
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:S7.Net.ErrorCode.WriteData">
|
||||
<summary>
|
||||
Error on write data
|
||||
</summary>
|
||||
</member>
|
||||
<member name="T:S7.Net.DataType">
|
||||
<summary>
|
||||
Types of memory area that can be read
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:S7.Net.DataType.Input">
|
||||
<summary>
|
||||
Input area memory
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:S7.Net.DataType.Output">
|
||||
<summary>
|
||||
Output area memory
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:S7.Net.DataType.Memory">
|
||||
<summary>
|
||||
Merkers area memory (M0, M0.0, ...)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:S7.Net.DataType.DataBlock">
|
||||
<summary>
|
||||
DB area memory (DB1, DB2, ...)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:S7.Net.DataType.Timer">
|
||||
<summary>
|
||||
Timer area memory(T1, T2, ...)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:S7.Net.DataType.Counter">
|
||||
<summary>
|
||||
Counter area memory (C1, C2, ...)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="T:S7.Net.VarType">
|
||||
<summary>
|
||||
Types
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:S7.Net.VarType.Bit">
|
||||
<summary>
|
||||
S7 Bit variable type (bool)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:S7.Net.VarType.Byte">
|
||||
<summary>
|
||||
S7 Byte variable type (8 bits)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:S7.Net.VarType.Word">
|
||||
<summary>
|
||||
S7 Word variable type (16 bits, 2 bytes)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:S7.Net.VarType.DWord">
|
||||
<summary>
|
||||
S7 DWord variable type (32 bits, 4 bytes)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:S7.Net.VarType.Int">
|
||||
<summary>
|
||||
S7 Int variable type (16 bits, 2 bytes)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:S7.Net.VarType.DInt">
|
||||
<summary>
|
||||
DInt variable type (32 bits, 4 bytes)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:S7.Net.VarType.Real">
|
||||
<summary>
|
||||
Real variable type (32 bits, 4 bytes)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:S7.Net.VarType.String">
|
||||
<summary>
|
||||
String variable type (variable)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:S7.Net.VarType.Timer">
|
||||
<summary>
|
||||
Timer variable type
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:S7.Net.VarType.Counter">
|
||||
<summary>
|
||||
Counter variable type
|
||||
</summary>
|
||||
</member>
|
||||
<member name="T:S7.Net.Plc">
|
||||
<summary>
|
||||
Creates an instance of S7.Net driver
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:S7.Net.Plc.IP">
|
||||
<summary>
|
||||
Ip address of the plc
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:S7.Net.Plc.CPU">
|
||||
<summary>
|
||||
Cpu type of the plc
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:S7.Net.Plc.Rack">
|
||||
<summary>
|
||||
Rack of the plc
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:S7.Net.Plc.Slot">
|
||||
<summary>
|
||||
Slot of the CPU of the plc
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:S7.Net.Plc.IsAvailable">
|
||||
<summary>
|
||||
Returns true if a connection to the plc can be established
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:S7.Net.Plc.IsConnected">
|
||||
<summary>
|
||||
Checks if the socket is connected and polls the other peer (the plc) to see if it's connected.
|
||||
This is the variable that you should continously check to see if the communication is working
|
||||
See also: http://stackoverflow.com/questions/2661764/how-to-check-if-a-socket-is-connected-disconnected-in-c
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:S7.Net.Plc.LastErrorString">
|
||||
<summary>
|
||||
Contains the last error registered when executing a function
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:S7.Net.Plc.LastErrorCode">
|
||||
<summary>
|
||||
Contains the last error code registered when executing a function
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:S7.Net.Plc.#ctor(S7.Net.CpuType,System.String,System.Int16,System.Int16)">
|
||||
<summary>
|
||||
Creates a PLC object with all the parameters needed for connections.
|
||||
For S7-1200 and S7-1500, the default is rack = 0 and slot = 0.
|
||||
You need slot > 0 if you are connecting to external ethernet card (CP).
|
||||
For S7-300 and S7-400 the default is rack = 0 and slot = 2.
|
||||
</summary>
|
||||
<param name="cpu">CpuType of the plc (select from the enum)</param>
|
||||
<param name="ip">Ip address of the plc</param>
|
||||
<param name="rack">rack of the plc, usually it's 0, but check in the hardware configuration of Step7 or TIA portal</param>
|
||||
<param name="slot">slot of the CPU of the plc, usually it's 2 for S7300-S7400, 0 for S7-1200 and S7-1500.
|
||||
If you use an external ethernet card, this must be set accordingly.</param>
|
||||
</member>
|
||||
<member name="M:S7.Net.Plc.Open">
|
||||
<summary>
|
||||
Open a socket and connects to the plc, sending all the corrected package and returning if the connection was successful (ErroreCode.NoError) of it was wrong.
|
||||
</summary>
|
||||
<returns>Returns ErrorCode.NoError if the connection was successful, otherwise check the ErrorCode</returns>
|
||||
</member>
|
||||
<member name="M:S7.Net.Plc.Close">
|
||||
<summary>
|
||||
Disonnects from the plc and close the socket
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:S7.Net.Plc.ReadMultipleVars(System.Collections.Generic.List{S7.Net.Types.DataItem})">
|
||||
<summary>
|
||||
Reads multiple vars in a single request.
|
||||
You have to create and pass a list of DataItems and you obtain in response the same list with the values.
|
||||
Values are stored in the property "Value" of the dataItem and are already converted.
|
||||
If you don't want the conversion, just create a dataItem of bytes.
|
||||
DataItems must not be more than 20 (protocol restriction) and bytes must not be more than 200 + 22 of header (protocol restriction).
|
||||
</summary>
|
||||
<param name="dataItems">List of dataitems that contains the list of variables that must be read. Maximum 20 dataitems are accepted.</param>
|
||||
</member>
|
||||
<member name="M:S7.Net.Plc.ReadBytes(S7.Net.DataType,System.Int32,System.Int32,System.Int32)">
|
||||
<summary>
|
||||
Reads a number of bytes from a DB starting from a specified index. This handles more than 200 bytes with multiple requests.
|
||||
If the read was not successful, check LastErrorCode or LastErrorString.
|
||||
</summary>
|
||||
<param name="dataType">Data type of the memory area, can be DB, Timer, Counter, Merker(Memory), Input, Output.</param>
|
||||
<param name="db">Address of the memory area (if you want to read DB1, this is set to 1). This must be set also for other memory area types: counters, timers,etc.</param>
|
||||
<param name="startByteAdr">Start byte address. If you want to read DB1.DBW200, this is 200.</param>
|
||||
<param name="count">Byte count, if you want to read 120 bytes, set this to 120.</param>
|
||||
<returns>Returns the bytes in an array</returns>
|
||||
</member>
|
||||
<member name="M:S7.Net.Plc.Read(S7.Net.DataType,System.Int32,System.Int32,S7.Net.VarType,System.Int32)">
|
||||
<summary>
|
||||
Read and decode a certain number of bytes of the "VarType" provided.
|
||||
This can be used to read multiple consecutive variables of the same type (Word, DWord, Int, etc).
|
||||
If the read was not successful, check LastErrorCode or LastErrorString.
|
||||
</summary>
|
||||
<param name="dataType">Data type of the memory area, can be DB, Timer, Counter, Merker(Memory), Input, Output.</param>
|
||||
<param name="db">Address of the memory area (if you want to read DB1, this is set to 1). This must be set also for other memory area types: counters, timers,etc.</param>
|
||||
<param name="startByteAdr">Start byte address. If you want to read DB1.DBW200, this is 200.</param>
|
||||
<param name="varType">Type of the variable/s that you are reading</param>
|
||||
<param name="varCount"></param>
|
||||
</member>
|
||||
<member name="M:S7.Net.Plc.Read(System.String)">
|
||||
<summary>
|
||||
Reads a single variable from the plc, takes in input strings like "DB1.DBX0.0", "DB20.DBD200", "MB20", "T45", etc.
|
||||
If the read was not successful, check LastErrorCode or LastErrorString.
|
||||
</summary>
|
||||
<param name="variable">Input strings like "DB1.DBX0.0", "DB20.DBD200", "MB20", "T45", etc.</param>
|
||||
<returns>Returns an object that contains the value. This object must be cast accordingly.</returns>
|
||||
</member>
|
||||
<member name="M:S7.Net.Plc.ReadStruct(System.Type,System.Int32,System.Int32)">
|
||||
<summary>
|
||||
Reads all the bytes needed to fill a struct in C#, starting from a certain address, and return an object that can be casted to the struct.
|
||||
</summary>
|
||||
<param name="structType">Type of the struct to be readed (es.: TypeOf(MyStruct)).</param>
|
||||
<param name="db">Address of the DB.</param>
|
||||
<param name="startByteAdr">Start byte address. If you want to read DB1.DBW200, this is 200.</param>
|
||||
<returns>Returns a struct that must be cast.</returns>
|
||||
</member>
|
||||
<member name="M:S7.Net.Plc.ReadStruct``1(System.Int32,System.Int32)">
|
||||
<summary>
|
||||
Reads all the bytes needed to fill a struct in C#, starting from a certain address, and returns the struct or null if nothing was read.
|
||||
</summary>
|
||||
<typeparam name="T">The struct type</typeparam>
|
||||
<param name="db">Address of the DB.</param>
|
||||
<param name="startByteAdr">Start byte address. If you want to read DB1.DBW200, this is 200.</param>
|
||||
<returns>Returns a nulable struct. If nothing was read null will be returned.</returns>
|
||||
</member>
|
||||
<member name="M:S7.Net.Plc.ReadClass(System.Object,System.Int32,System.Int32)">
|
||||
<summary>
|
||||
Reads all the bytes needed to fill a class in C#, starting from a certain address, and set all the properties values to the value that are read from the plc.
|
||||
This reads only properties, it doesn't read private variable or public variable without {get;set;} specified.
|
||||
</summary>
|
||||
<param name="sourceClass">Instance of the class that will store the values</param>
|
||||
<param name="db">Index of the DB; es.: 1 is for DB1</param>
|
||||
<param name="startByteAdr">Start byte address. If you want to read DB1.DBW200, this is 200.</param>
|
||||
<returns>The number of read bytes</returns>
|
||||
</member>
|
||||
<member name="M:S7.Net.Plc.ReadClass``1(System.Int32,System.Int32)">
|
||||
<summary>
|
||||
Reads all the bytes needed to fill a class in C#, starting from a certain address, and set all the properties values to the value that are read from the plc.
|
||||
This reads only properties, it doesn't read private variable or public variable without {get;set;} specified. To instantiate the class defined by the generic
|
||||
type, the class needs a default constructor.
|
||||
</summary>
|
||||
<typeparam name="T">The class that will be instantiated. Requires a default constructor</typeparam>
|
||||
<param name="db">Index of the DB; es.: 1 is for DB1</param>
|
||||
<param name="startByteAdr">Start byte address. If you want to read DB1.DBW200, this is 200.</param>
|
||||
<returns>An instance of the class with the values read from the plc. If no data has been read, null will be returned</returns>
|
||||
</member>
|
||||
<member name="M:S7.Net.Plc.ReadClass``1(System.Func{``0},System.Int32,System.Int32)">
|
||||
<summary>
|
||||
Reads all the bytes needed to fill a class in C#, starting from a certain address, and set all the properties values to the value that are read from the plc.
|
||||
This reads only properties, it doesn't read private variable or public variable without {get;set;} specified.
|
||||
</summary>
|
||||
<typeparam name="T">The class that will be instantiated</typeparam>
|
||||
<param name="classFactory">Function to instantiate the class</param>
|
||||
<param name="db">Index of the DB; es.: 1 is for DB1</param>
|
||||
<param name="startByteAdr">Start byte address. If you want to read DB1.DBW200, this is 200.</param>
|
||||
<returns>An instance of the class with the values read from the plc. If no data has been read, null will be returned</returns>
|
||||
</member>
|
||||
<member name="M:S7.Net.Plc.WriteBytes(S7.Net.DataType,System.Int32,System.Int32,System.Byte[])">
|
||||
<summary>
|
||||
Write a number of bytes from a DB starting from a specified index. This handles more than 200 bytes with multiple requests.
|
||||
If the write was not successful, check LastErrorCode or LastErrorString.
|
||||
</summary>
|
||||
<param name="dataType">Data type of the memory area, can be DB, Timer, Counter, Merker(Memory), Input, Output.</param>
|
||||
<param name="db">Address of the memory area (if you want to read DB1, this is set to 1). This must be set also for other memory area types: counters, timers,etc.</param>
|
||||
<param name="startByteAdr">Start byte address. If you want to write DB1.DBW200, this is 200.</param>
|
||||
<param name="value">Bytes to write. If more than 200, multiple requests will be made.</param>
|
||||
<returns>NoError if it was successful, or the error is specified</returns>
|
||||
</member>
|
||||
<member name="M:S7.Net.Plc.WriteBit(S7.Net.DataType,System.Int32,System.Int32,System.Int32,System.Boolean)">
|
||||
<summary>
|
||||
Write a single bit from a DB with the specified index.
|
||||
</summary>
|
||||
<param name="dataType">Data type of the memory area, can be DB, Timer, Counter, Merker(Memory), Input, Output.</param>
|
||||
<param name="db">Address of the memory area (if you want to read DB1, this is set to 1). This must be set also for other memory area types: counters, timers,etc.</param>
|
||||
<param name="startByteAdr">Start byte address. If you want to write DB1.DBW200, this is 200.</param>
|
||||
<param name="bitAdr">The address of the bit. (0-7)</param>
|
||||
<param name="value">Bytes to write. If more than 200, multiple requests will be made.</param>
|
||||
<returns>NoError if it was successful, or the error is specified</returns>
|
||||
</member>
|
||||
<member name="M:S7.Net.Plc.WriteBit(S7.Net.DataType,System.Int32,System.Int32,System.Int32,System.Int32)">
|
||||
<summary>
|
||||
Write a single bit from a DB with the specified index.
|
||||
</summary>
|
||||
<param name="dataType">Data type of the memory area, can be DB, Timer, Counter, Merker(Memory), Input, Output.</param>
|
||||
<param name="db">Address of the memory area (if you want to read DB1, this is set to 1). This must be set also for other memory area types: counters, timers,etc.</param>
|
||||
<param name="startByteAdr">Start byte address. If you want to write DB1.DBW200, this is 200.</param>
|
||||
<param name="bitAdr">The address of the bit. (0-7)</param>
|
||||
<param name="value">Bytes to write. If more than 200, multiple requests will be made.</param>
|
||||
<returns>NoError if it was successful, or the error is specified</returns>
|
||||
</member>
|
||||
<member name="M:S7.Net.Plc.Write(S7.Net.DataType,System.Int32,System.Int32,System.Object,System.Int32)">
|
||||
<summary>
|
||||
Takes in input an object and tries to parse it to an array of values. This can be used to write many data, all of the same type.
|
||||
You must specify the memory area type, memory are address, byte start address and bytes count.
|
||||
If the read was not successful, check LastErrorCode or LastErrorString.
|
||||
</summary>
|
||||
<param name="dataType">Data type of the memory area, can be DB, Timer, Counter, Merker(Memory), Input, Output.</param>
|
||||
<param name="db">Address of the memory area (if you want to read DB1, this is set to 1). This must be set also for other memory area types: counters, timers,etc.</param>
|
||||
<param name="startByteAdr">Start byte address. If you want to read DB1.DBW200, this is 200.</param>
|
||||
<param name="value">Bytes to write. The lenght of this parameter can't be higher than 200. If you need more, use recursion.</param>
|
||||
<param name="bitAdr">The address of the bit. (0-7)</param>
|
||||
<returns>NoError if it was successful, or the error is specified</returns>
|
||||
</member>
|
||||
<member name="M:S7.Net.Plc.Write(System.String,System.Object)">
|
||||
<summary>
|
||||
Writes a single variable from the plc, takes in input strings like "DB1.DBX0.0", "DB20.DBD200", "MB20", "T45", etc.
|
||||
If the write was not successful, check LastErrorCode or LastErrorString.
|
||||
</summary>
|
||||
<param name="variable">Input strings like "DB1.DBX0.0", "DB20.DBD200", "MB20", "T45", etc.</param>
|
||||
<param name="value">Value to be written to the plc</param>
|
||||
<returns>NoError if it was successful, or the error is specified</returns>
|
||||
</member>
|
||||
<member name="M:S7.Net.Plc.WriteStruct(System.Object,System.Int32,System.Int32)">
|
||||
<summary>
|
||||
Writes a C# struct to a DB in the plc
|
||||
</summary>
|
||||
<param name="structValue">The struct to be written</param>
|
||||
<param name="db">Db address</param>
|
||||
<param name="startByteAdr">Start bytes on the plc</param>
|
||||
<returns>NoError if it was successful, or the error is specified</returns>
|
||||
</member>
|
||||
<member name="M:S7.Net.Plc.WriteClass(System.Object,System.Int32,System.Int32)">
|
||||
<summary>
|
||||
Writes a C# class to a DB in the plc
|
||||
</summary>
|
||||
<param name="classValue">The class to be written</param>
|
||||
<param name="db">Db address</param>
|
||||
<param name="startByteAdr">Start bytes on the plc</param>
|
||||
<returns>NoError if it was successful, or the error is specified</returns>
|
||||
</member>
|
||||
<member name="M:S7.Net.Plc.ClearLastError">
|
||||
<summary>
|
||||
Sets the LastErrorCode to NoError and LastErrorString to String.Empty
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:S7.Net.Plc.ReadHeaderPackage(System.Int32)">
|
||||
<summary>
|
||||
Creates the header to read bytes from the plc
|
||||
</summary>
|
||||
<param name="amount"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:S7.Net.Plc.CreateReadDataRequestPackage(S7.Net.DataType,System.Int32,System.Int32,System.Int32)">
|
||||
<summary>
|
||||
Create the bytes-package to request data from the plc. You have to specify the memory type (dataType),
|
||||
the address of the memory, the address of the byte and the bytes count.
|
||||
</summary>
|
||||
<param name="dataType">MemoryType (DB, Timer, Counter, etc.)</param>
|
||||
<param name="db">Address of the memory to be read</param>
|
||||
<param name="startByteAdr">Start address of the byte</param>
|
||||
<param name="count">Number of bytes to be read</param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:S7.Net.Plc.WriteBytesWithASingleRequest(S7.Net.DataType,System.Int32,System.Int32,System.Byte[])">
|
||||
<summary>
|
||||
Writes up to 200 bytes to the plc and returns NoError if successful. You must specify the memory area type, memory are address, byte start address and bytes count.
|
||||
If the write was not successful, check LastErrorCode or LastErrorString.
|
||||
</summary>
|
||||
<param name="dataType">Data type of the memory area, can be DB, Timer, Counter, Merker(Memory), Input, Output.</param>
|
||||
<param name="db">Address of the memory area (if you want to read DB1, this is set to 1). This must be set also for other memory area types: counters, timers,etc.</param>
|
||||
<param name="startByteAdr">Start byte address. If you want to read DB1.DBW200, this is 200.</param>
|
||||
<param name="value">Bytes to write. The lenght of this parameter can't be higher than 200. If you need more, use recursion.</param>
|
||||
<returns>NoError if it was successful, or the error is specified</returns>
|
||||
</member>
|
||||
<member name="M:S7.Net.Plc.ParseBytes(S7.Net.VarType,System.Byte[],System.Int32)">
|
||||
<summary>
|
||||
Given a S7 variable type (Bool, Word, DWord, etc.), it converts the bytes in the appropriate C# format.
|
||||
</summary>
|
||||
<param name="varType"></param>
|
||||
<param name="bytes"></param>
|
||||
<param name="varCount"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:S7.Net.Plc.VarTypeToByteLength(S7.Net.VarType,System.Int32)">
|
||||
<summary>
|
||||
Given a S7 variable type (Bool, Word, DWord, etc.), it returns how many bytes to read.
|
||||
</summary>
|
||||
<param name="varType"></param>
|
||||
<param name="varCount"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:S7.Net.Plc.Dispose">
|
||||
<summary>
|
||||
Releases all resources, disonnects from the plc and closes the socket
|
||||
</summary>
|
||||
</member>
|
||||
<member name="T:S7.Net.Types.Boolean">
|
||||
<summary>
|
||||
Contains the methods to read, set and reset bits inside bytes
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:S7.Net.Types.Boolean.GetValue(System.Byte,System.Int32)">
|
||||
<summary>
|
||||
Returns the value of a bit in a bit, given the address of the bit
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:S7.Net.Types.Boolean.SetBit(System.Byte,System.Int32)">
|
||||
<summary>
|
||||
Sets the value of a bit to 1 (true), given the address of the bit
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:S7.Net.Types.Boolean.ClearBit(System.Byte,System.Int32)">
|
||||
<summary>
|
||||
Resets the value of a bit to 0 (false), given the address of the bit
|
||||
</summary>
|
||||
</member>
|
||||
<member name="T:S7.Net.Types.Byte">
|
||||
<summary>
|
||||
Contains the methods to convert from bytes to byte arrays
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:S7.Net.Types.Byte.ToByteArray(System.Byte)">
|
||||
<summary>
|
||||
Converts a byte to byte array
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:S7.Net.Types.Byte.FromByteArray(System.Byte[])">
|
||||
<summary>
|
||||
Converts a byte array to byte
|
||||
</summary>
|
||||
<param name="bytes"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="T:S7.Net.Types.Class">
|
||||
<summary>
|
||||
Contains the methods to convert a C# class to S7 data types
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:S7.Net.Types.Class.GetClassSize(System.Object)">
|
||||
<summary>
|
||||
Gets the size of the class in bytes.
|
||||
</summary>
|
||||
<param name="instance">An instance of the class</param>
|
||||
<returns>the number of bytes</returns>
|
||||
</member>
|
||||
<member name="M:S7.Net.Types.Class.FromBytes(System.Object,System.Byte[])">
|
||||
<summary>
|
||||
Sets the object's values with the given array of bytes
|
||||
</summary>
|
||||
<param name="sourceClass">The object to fill in the given array of bytes</param>
|
||||
<param name="bytes">The array of bytes</param>
|
||||
</member>
|
||||
<member name="M:S7.Net.Types.Class.ToBytes(System.Object)">
|
||||
<summary>
|
||||
Creates a byte array depending on the struct type.
|
||||
</summary>
|
||||
<param name="sourceClass">The struct object</param>
|
||||
<returns>A byte array or null if fails.</returns>
|
||||
</member>
|
||||
<member name="T:S7.Net.Types.Counter">
|
||||
<summary>
|
||||
Contains the conversion methods to convert Counter from S7 plc to C# ushort (UInt16).
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:S7.Net.Types.Counter.FromByteArray(System.Byte[])">
|
||||
<summary>
|
||||
Converts a Counter (2 bytes) to ushort (UInt16)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:S7.Net.Types.Counter.FromBytes(System.Byte,System.Byte)">
|
||||
<summary>
|
||||
Converts a Counter (2 bytes) to ushort (UInt16)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:S7.Net.Types.Counter.ToByteArray(System.UInt16)">
|
||||
<summary>
|
||||
Converts a ushort (UInt16) to word (2 bytes)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:S7.Net.Types.Counter.ToByteArray(System.UInt16[])">
|
||||
<summary>
|
||||
Converts an array of ushort (UInt16) to an array of bytes
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:S7.Net.Types.Counter.ToArray(System.Byte[])">
|
||||
<summary>
|
||||
Converts an array of bytes to an array of ushort
|
||||
</summary>
|
||||
</member>
|
||||
<member name="T:S7.Net.Types.DataItem">
|
||||
<summary>
|
||||
Create an instance of a memory block that can be read by using ReadMultipleVars
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:S7.Net.Types.DataItem.DataType">
|
||||
<summary>
|
||||
Memory area to read
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:S7.Net.Types.DataItem.VarType">
|
||||
<summary>
|
||||
Type of data to be read (default is bytes)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:S7.Net.Types.DataItem.DB">
|
||||
<summary>
|
||||
Address of memory area to read (example: for DB1 this value is 1, for T45 this value is 45)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:S7.Net.Types.DataItem.StartByteAdr">
|
||||
<summary>
|
||||
Address of the first byte to read
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:S7.Net.Types.DataItem.Count">
|
||||
<summary>
|
||||
Number of variables to read
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:S7.Net.Types.DataItem.Value">
|
||||
<summary>
|
||||
Contains the value of the memory area after the read has been executed
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:S7.Net.Types.DataItem.#ctor">
|
||||
<summary>
|
||||
Create an instance of DataItem
|
||||
</summary>
|
||||
</member>
|
||||
<member name="T:S7.Net.Types.DInt">
|
||||
<summary>
|
||||
Contains the conversion methods to convert DInt from S7 plc to C# int (Int32).
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:S7.Net.Types.DInt.FromByteArray(System.Byte[])">
|
||||
<summary>
|
||||
Converts a S7 DInt (4 bytes) to int (Int32)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:S7.Net.Types.DInt.FromBytes(System.Byte,System.Byte,System.Byte,System.Byte)">
|
||||
<summary>
|
||||
Converts a S7 DInt (4 bytes) to int (Int32)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:S7.Net.Types.DInt.ToByteArray(System.Int32)">
|
||||
<summary>
|
||||
Converts a int (Int32) to S7 DInt (4 bytes)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:S7.Net.Types.DInt.ToByteArray(System.Int32[])">
|
||||
<summary>
|
||||
Converts an array of int (Int32) to an array of bytes
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:S7.Net.Types.DInt.ToArray(System.Byte[])">
|
||||
<summary>
|
||||
Converts an array of S7 DInt to an array of int (Int32)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:S7.Net.Types.DInt.CDWord(System.Int64)">
|
||||
<summary>
|
||||
Converts from C# long (Int64) to C# int (Int32)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="T:S7.Net.Types.Double">
|
||||
<summary>
|
||||
Contains the conversion methods to convert Real from S7 plc to C# double.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:S7.Net.Types.Double.FromByteArray(System.Byte[])">
|
||||
<summary>
|
||||
Converts a S7 Real (4 bytes) to double
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:S7.Net.Types.Double.FromDWord(System.Int32)">
|
||||
<summary>
|
||||
Converts a S7 DInt to double
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:S7.Net.Types.Double.FromDWord(System.UInt32)">
|
||||
<summary>
|
||||
Converts a S7 DWord to double
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:S7.Net.Types.Double.ToByteArray(System.Double)">
|
||||
<summary>
|
||||
Converts a double to S7 Real (4 bytes)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:S7.Net.Types.Double.ToByteArray(System.Double[])">
|
||||
<summary>
|
||||
Converts an array of double to an array of bytes
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:S7.Net.Types.Double.ToArray(System.Byte[])">
|
||||
<summary>
|
||||
Converts an array of S7 Real to an array of double
|
||||
</summary>
|
||||
</member>
|
||||
<member name="T:S7.Net.Types.DWord">
|
||||
<summary>
|
||||
Contains the conversion methods to convert DWord from S7 plc to C#.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:S7.Net.Types.DWord.FromByteArray(System.Byte[])">
|
||||
<summary>
|
||||
Converts a S7 DWord (4 bytes) to uint (UInt32)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:S7.Net.Types.DWord.FromBytes(System.Byte,System.Byte,System.Byte,System.Byte)">
|
||||
<summary>
|
||||
Converts a S7 DWord (4 bytes) to uint (UInt32)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:S7.Net.Types.DWord.ToByteArray(System.UInt32)">
|
||||
<summary>
|
||||
Converts a uint (UInt32) to S7 DWord (4 bytes)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:S7.Net.Types.DWord.ToByteArray(System.UInt32[])">
|
||||
<summary>
|
||||
Converts an array of uint (UInt32) to an array of S7 DWord (4 bytes)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:S7.Net.Types.DWord.ToArray(System.Byte[])">
|
||||
<summary>
|
||||
Converts an array of S7 DWord to an array of uint (UInt32)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="T:S7.Net.Types.Int">
|
||||
<summary>
|
||||
Contains the conversion methods to convert Int from S7 plc to C#.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:S7.Net.Types.Int.FromByteArray(System.Byte[])">
|
||||
<summary>
|
||||
Converts a S7 Int (2 bytes) to short (Int16)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:S7.Net.Types.Int.FromBytes(System.Byte,System.Byte)">
|
||||
<summary>
|
||||
Converts a S7 Int (2 bytes) to short (Int16)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:S7.Net.Types.Int.ToByteArray(System.Int16)">
|
||||
<summary>
|
||||
Converts a short (Int16) to a S7 Int byte array (2 bytes)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:S7.Net.Types.Int.ToByteArray(System.Int16[])">
|
||||
<summary>
|
||||
Converts an array of short (Int16) to a S7 Int byte array (2 bytes)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:S7.Net.Types.Int.ToArray(System.Byte[])">
|
||||
<summary>
|
||||
Converts an array of S7 Int to an array of short (Int16)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:S7.Net.Types.Int.CWord(System.Int32)">
|
||||
<summary>
|
||||
Converts a C# int value to a C# short value, to be used as word.
|
||||
</summary>
|
||||
<param name="value"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="T:S7.Net.Types.String">
|
||||
<summary>
|
||||
Contains the methods to convert from S7 strings to C# strings
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:S7.Net.Types.String.ToByteArray(System.String)">
|
||||
<summary>
|
||||
Converts a string to S7 bytes
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:S7.Net.Types.String.FromByteArray(System.Byte[])">
|
||||
<summary>
|
||||
Converts S7 bytes to a string
|
||||
</summary>
|
||||
<param name="bytes"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="T:S7.Net.Types.Struct">
|
||||
<summary>
|
||||
Contains the method to convert a C# struct to S7 data types
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:S7.Net.Types.Struct.GetStructSize(System.Type)">
|
||||
<summary>
|
||||
Gets the size of the struct in bytes.
|
||||
</summary>
|
||||
<param name="structType">the type of the struct</param>
|
||||
<returns>the number of bytes</returns>
|
||||
</member>
|
||||
<member name="M:S7.Net.Types.Struct.FromBytes(System.Type,System.Byte[])">
|
||||
<summary>
|
||||
Creates a struct of a specified type by an array of bytes.
|
||||
</summary>
|
||||
<param name="structType">The struct type</param>
|
||||
<param name="bytes">The array of bytes</param>
|
||||
<returns>The object depending on the struct type or null if fails(array-length != struct-length</returns>
|
||||
</member>
|
||||
<member name="M:S7.Net.Types.Struct.ToBytes(System.Object)">
|
||||
<summary>
|
||||
Creates a byte array depending on the struct type.
|
||||
</summary>
|
||||
<param name="structValue">The struct object</param>
|
||||
<returns>A byte array or null if fails.</returns>
|
||||
</member>
|
||||
<member name="T:S7.Net.Types.Timer">
|
||||
<summary>
|
||||
Converts the Timer data type to C# data type
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:S7.Net.Types.Timer.FromByteArray(System.Byte[])">
|
||||
<summary>
|
||||
Converts the timer bytes to a double
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:S7.Net.Types.Timer.ToByteArray(System.UInt16)">
|
||||
<summary>
|
||||
Converts a ushort (UInt16) to an array of bytes formatted as time
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:S7.Net.Types.Timer.ToByteArray(System.UInt16[])">
|
||||
<summary>
|
||||
Converts an array of ushorts (Uint16) to an array of bytes formatted as time
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:S7.Net.Types.Timer.ToArray(System.Byte[])">
|
||||
<summary>
|
||||
Converts an array of bytes formatted as time to an array of doubles
|
||||
</summary>
|
||||
<param name="bytes"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="T:S7.Net.Types.Word">
|
||||
<summary>
|
||||
Contains the conversion methods to convert Words from S7 plc to C#.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:S7.Net.Types.Word.FromByteArray(System.Byte[])">
|
||||
<summary>
|
||||
Converts a word (2 bytes) to ushort (UInt16)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:S7.Net.Types.Word.FromBytes(System.Byte,System.Byte)">
|
||||
<summary>
|
||||
Converts a word (2 bytes) to ushort (UInt16)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:S7.Net.Types.Word.ToByteArray(System.UInt16)">
|
||||
<summary>
|
||||
Converts a ushort (UInt16) to word (2 bytes)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:S7.Net.Types.Word.ToByteArray(System.UInt16[])">
|
||||
<summary>
|
||||
Converts an array of ushort (UInt16) to an array of bytes
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:S7.Net.Types.Word.ToArray(System.Byte[])">
|
||||
<summary>
|
||||
Converts an array of bytes to an array of ushort
|
||||
</summary>
|
||||
</member>
|
||||
</members>
|
||||
</doc>
|
||||
Binary file not shown.
@@ -1,917 +0,0 @@
|
||||
<?xml version="1.0"?>
|
||||
<doc>
|
||||
<assembly>
|
||||
<name>S7.Net</name>
|
||||
</assembly>
|
||||
<members>
|
||||
<member name="T:S7.Net.Conversion">
|
||||
<summary>
|
||||
Conversion methods to convert from Siemens numeric format to C# and back
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:S7.Net.Conversion.BinStringToInt32(System.String)">
|
||||
<summary>
|
||||
Converts a binary string to Int32 value
|
||||
</summary>
|
||||
<param name="txt"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:S7.Net.Conversion.BinStringToByte(System.String)">
|
||||
<summary>
|
||||
Converts a binary string to a byte. Can return null.
|
||||
</summary>
|
||||
<param name="txt"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:S7.Net.Conversion.ValToBinString(System.Object)">
|
||||
<summary>
|
||||
Converts the value to a binary string
|
||||
</summary>
|
||||
<param name="value"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:S7.Net.Conversion.SelectBit(System.Byte,System.Int32)">
|
||||
<summary>
|
||||
Helper to get a bit value given a byte and the bit index.
|
||||
Example: DB1.DBX0.5 -> var bytes = ReadBytes(DB1.DBW0); bool bit = bytes[0].SelectBit(5);
|
||||
</summary>
|
||||
<param name="data"></param>
|
||||
<param name="bitPosition"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:S7.Net.Conversion.ConvertToShort(System.UInt16)">
|
||||
<summary>
|
||||
Converts from ushort value to short value; it's used to retrieve negative values from words
|
||||
</summary>
|
||||
<param name="input"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:S7.Net.Conversion.ConvertToUshort(System.Int16)">
|
||||
<summary>
|
||||
Converts from short value to ushort value; it's used to pass negative values to DWs
|
||||
</summary>
|
||||
<param name="input"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:S7.Net.Conversion.ConvertToInt(System.UInt32)">
|
||||
<summary>
|
||||
Converts from UInt32 value to Int32 value; it's used to retrieve negative values from DBDs
|
||||
</summary>
|
||||
<param name="input"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:S7.Net.Conversion.ConvertToUInt(System.Int32)">
|
||||
<summary>
|
||||
Converts from Int32 value to UInt32 value; it's used to pass negative values to DBDs
|
||||
</summary>
|
||||
<param name="input"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:S7.Net.Conversion.ConvertToUInt(System.Double)">
|
||||
<summary>
|
||||
Converts from double to DWord (DBD)
|
||||
</summary>
|
||||
<param name="input"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:S7.Net.Conversion.ConvertToDouble(System.UInt32)">
|
||||
<summary>
|
||||
Converts from DWord (DBD) to double
|
||||
</summary>
|
||||
<param name="input"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="T:S7.Net.CpuType">
|
||||
<summary>
|
||||
Types of S7 cpu supported by the library
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:S7.Net.CpuType.S7200">
|
||||
<summary>
|
||||
S7 200 cpu type
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:S7.Net.CpuType.S7300">
|
||||
<summary>
|
||||
S7 300 cpu type
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:S7.Net.CpuType.S7400">
|
||||
<summary>
|
||||
S7 400 cpu type
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:S7.Net.CpuType.S71200">
|
||||
<summary>
|
||||
S7 1200 cpu type
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:S7.Net.CpuType.S71500">
|
||||
<summary>
|
||||
S7 1500 cpu type
|
||||
</summary>
|
||||
</member>
|
||||
<member name="T:S7.Net.ErrorCode">
|
||||
<summary>
|
||||
Types of error code that can be set after a function is called
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:S7.Net.ErrorCode.NoError">
|
||||
<summary>
|
||||
The function has been executed correctly
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:S7.Net.ErrorCode.WrongCPU_Type">
|
||||
<summary>
|
||||
Wrong type of CPU error
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:S7.Net.ErrorCode.ConnectionError">
|
||||
<summary>
|
||||
Connection error
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:S7.Net.ErrorCode.IPAddressNotAvailable">
|
||||
<summary>
|
||||
Ip address not available
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:S7.Net.ErrorCode.WrongVarFormat">
|
||||
<summary>
|
||||
Wrong format of the variable
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:S7.Net.ErrorCode.WrongNumberReceivedBytes">
|
||||
<summary>
|
||||
Wrong number of received bytes
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:S7.Net.ErrorCode.SendData">
|
||||
<summary>
|
||||
Error on send data
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:S7.Net.ErrorCode.ReadData">
|
||||
<summary>
|
||||
Error on read data
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:S7.Net.ErrorCode.WriteData">
|
||||
<summary>
|
||||
Error on write data
|
||||
</summary>
|
||||
</member>
|
||||
<member name="T:S7.Net.DataType">
|
||||
<summary>
|
||||
Types of memory area that can be read
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:S7.Net.DataType.Input">
|
||||
<summary>
|
||||
Input area memory
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:S7.Net.DataType.Output">
|
||||
<summary>
|
||||
Output area memory
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:S7.Net.DataType.Memory">
|
||||
<summary>
|
||||
Merkers area memory (M0, M0.0, ...)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:S7.Net.DataType.DataBlock">
|
||||
<summary>
|
||||
DB area memory (DB1, DB2, ...)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:S7.Net.DataType.Timer">
|
||||
<summary>
|
||||
Timer area memory(T1, T2, ...)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:S7.Net.DataType.Counter">
|
||||
<summary>
|
||||
Counter area memory (C1, C2, ...)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="T:S7.Net.VarType">
|
||||
<summary>
|
||||
Types
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:S7.Net.VarType.Bit">
|
||||
<summary>
|
||||
S7 Bit variable type (bool)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:S7.Net.VarType.Byte">
|
||||
<summary>
|
||||
S7 Byte variable type (8 bits)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:S7.Net.VarType.Word">
|
||||
<summary>
|
||||
S7 Word variable type (16 bits, 2 bytes)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:S7.Net.VarType.DWord">
|
||||
<summary>
|
||||
S7 DWord variable type (32 bits, 4 bytes)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:S7.Net.VarType.Int">
|
||||
<summary>
|
||||
S7 Int variable type (16 bits, 2 bytes)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:S7.Net.VarType.DInt">
|
||||
<summary>
|
||||
DInt variable type (32 bits, 4 bytes)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:S7.Net.VarType.Real">
|
||||
<summary>
|
||||
Real variable type (32 bits, 4 bytes)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:S7.Net.VarType.String">
|
||||
<summary>
|
||||
String variable type (variable)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:S7.Net.VarType.Timer">
|
||||
<summary>
|
||||
Timer variable type
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:S7.Net.VarType.Counter">
|
||||
<summary>
|
||||
Counter variable type
|
||||
</summary>
|
||||
</member>
|
||||
<member name="T:S7.Net.Plc">
|
||||
<summary>
|
||||
Creates an instance of S7.Net driver
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:S7.Net.Plc.IP">
|
||||
<summary>
|
||||
Ip address of the plc
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:S7.Net.Plc.CPU">
|
||||
<summary>
|
||||
Cpu type of the plc
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:S7.Net.Plc.Rack">
|
||||
<summary>
|
||||
Rack of the plc
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:S7.Net.Plc.Slot">
|
||||
<summary>
|
||||
Slot of the CPU of the plc
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:S7.Net.Plc.IsAvailable">
|
||||
<summary>
|
||||
Returns true if a connection to the plc can be established
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:S7.Net.Plc.IsConnected">
|
||||
<summary>
|
||||
Checks if the socket is connected and polls the other peer (the plc) to see if it's connected.
|
||||
This is the variable that you should continously check to see if the communication is working
|
||||
See also: http://stackoverflow.com/questions/2661764/how-to-check-if-a-socket-is-connected-disconnected-in-c
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:S7.Net.Plc.LastErrorString">
|
||||
<summary>
|
||||
Contains the last error registered when executing a function
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:S7.Net.Plc.LastErrorCode">
|
||||
<summary>
|
||||
Contains the last error code registered when executing a function
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:S7.Net.Plc.#ctor(S7.Net.CpuType,System.String,System.Int16,System.Int16)">
|
||||
<summary>
|
||||
Creates a PLC object with all the parameters needed for connections.
|
||||
For S7-1200 and S7-1500, the default is rack = 0 and slot = 0.
|
||||
You need slot > 0 if you are connecting to external ethernet card (CP).
|
||||
For S7-300 and S7-400 the default is rack = 0 and slot = 2.
|
||||
</summary>
|
||||
<param name="cpu">CpuType of the plc (select from the enum)</param>
|
||||
<param name="ip">Ip address of the plc</param>
|
||||
<param name="rack">rack of the plc, usually it's 0, but check in the hardware configuration of Step7 or TIA portal</param>
|
||||
<param name="slot">slot of the CPU of the plc, usually it's 2 for S7300-S7400, 0 for S7-1200 and S7-1500.
|
||||
If you use an external ethernet card, this must be set accordingly.</param>
|
||||
</member>
|
||||
<member name="M:S7.Net.Plc.Open">
|
||||
<summary>
|
||||
Open a socket and connects to the plc, sending all the corrected package and returning if the connection was successful (ErroreCode.NoError) of it was wrong.
|
||||
</summary>
|
||||
<returns>Returns ErrorCode.NoError if the connection was successful, otherwise check the ErrorCode</returns>
|
||||
</member>
|
||||
<member name="M:S7.Net.Plc.Close">
|
||||
<summary>
|
||||
Disonnects from the plc and close the socket
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:S7.Net.Plc.ReadMultipleVars(System.Collections.Generic.List{S7.Net.Types.DataItem})">
|
||||
<summary>
|
||||
Reads multiple vars in a single request.
|
||||
You have to create and pass a list of DataItems and you obtain in response the same list with the values.
|
||||
Values are stored in the property "Value" of the dataItem and are already converted.
|
||||
If you don't want the conversion, just create a dataItem of bytes.
|
||||
DataItems must not be more than 20 (protocol restriction) and bytes must not be more than 200 + 22 of header (protocol restriction).
|
||||
</summary>
|
||||
<param name="dataItems">List of dataitems that contains the list of variables that must be read. Maximum 20 dataitems are accepted.</param>
|
||||
</member>
|
||||
<member name="M:S7.Net.Plc.ReadBytes(S7.Net.DataType,System.Int32,System.Int32,System.Int32)">
|
||||
<summary>
|
||||
Reads a number of bytes from a DB starting from a specified index. This handles more than 200 bytes with multiple requests.
|
||||
If the read was not successful, check LastErrorCode or LastErrorString.
|
||||
</summary>
|
||||
<param name="dataType">Data type of the memory area, can be DB, Timer, Counter, Merker(Memory), Input, Output.</param>
|
||||
<param name="db">Address of the memory area (if you want to read DB1, this is set to 1). This must be set also for other memory area types: counters, timers,etc.</param>
|
||||
<param name="startByteAdr">Start byte address. If you want to read DB1.DBW200, this is 200.</param>
|
||||
<param name="count">Byte count, if you want to read 120 bytes, set this to 120.</param>
|
||||
<returns>Returns the bytes in an array</returns>
|
||||
</member>
|
||||
<member name="M:S7.Net.Plc.Read(S7.Net.DataType,System.Int32,System.Int32,S7.Net.VarType,System.Int32)">
|
||||
<summary>
|
||||
Read and decode a certain number of bytes of the "VarType" provided.
|
||||
This can be used to read multiple consecutive variables of the same type (Word, DWord, Int, etc).
|
||||
If the read was not successful, check LastErrorCode or LastErrorString.
|
||||
</summary>
|
||||
<param name="dataType">Data type of the memory area, can be DB, Timer, Counter, Merker(Memory), Input, Output.</param>
|
||||
<param name="db">Address of the memory area (if you want to read DB1, this is set to 1). This must be set also for other memory area types: counters, timers,etc.</param>
|
||||
<param name="startByteAdr">Start byte address. If you want to read DB1.DBW200, this is 200.</param>
|
||||
<param name="varType">Type of the variable/s that you are reading</param>
|
||||
<param name="varCount"></param>
|
||||
</member>
|
||||
<member name="M:S7.Net.Plc.Read(System.String)">
|
||||
<summary>
|
||||
Reads a single variable from the plc, takes in input strings like "DB1.DBX0.0", "DB20.DBD200", "MB20", "T45", etc.
|
||||
If the read was not successful, check LastErrorCode or LastErrorString.
|
||||
</summary>
|
||||
<param name="variable">Input strings like "DB1.DBX0.0", "DB20.DBD200", "MB20", "T45", etc.</param>
|
||||
<returns>Returns an object that contains the value. This object must be cast accordingly.</returns>
|
||||
</member>
|
||||
<member name="M:S7.Net.Plc.ReadStruct(System.Type,System.Int32,System.Int32)">
|
||||
<summary>
|
||||
Reads all the bytes needed to fill a struct in C#, starting from a certain address, and return an object that can be casted to the struct.
|
||||
</summary>
|
||||
<param name="structType">Type of the struct to be readed (es.: TypeOf(MyStruct)).</param>
|
||||
<param name="db">Address of the DB.</param>
|
||||
<param name="startByteAdr">Start byte address. If you want to read DB1.DBW200, this is 200.</param>
|
||||
<returns>Returns a struct that must be cast.</returns>
|
||||
</member>
|
||||
<member name="M:S7.Net.Plc.ReadStruct``1(System.Int32,System.Int32)">
|
||||
<summary>
|
||||
Reads all the bytes needed to fill a struct in C#, starting from a certain address, and returns the struct or null if nothing was read.
|
||||
</summary>
|
||||
<typeparam name="T">The struct type</typeparam>
|
||||
<param name="db">Address of the DB.</param>
|
||||
<param name="startByteAdr">Start byte address. If you want to read DB1.DBW200, this is 200.</param>
|
||||
<returns>Returns a nulable struct. If nothing was read null will be returned.</returns>
|
||||
</member>
|
||||
<member name="M:S7.Net.Plc.ReadClass(System.Object,System.Int32,System.Int32)">
|
||||
<summary>
|
||||
Reads all the bytes needed to fill a class in C#, starting from a certain address, and set all the properties values to the value that are read from the plc.
|
||||
This reads only properties, it doesn't read private variable or public variable without {get;set;} specified.
|
||||
</summary>
|
||||
<param name="sourceClass">Instance of the class that will store the values</param>
|
||||
<param name="db">Index of the DB; es.: 1 is for DB1</param>
|
||||
<param name="startByteAdr">Start byte address. If you want to read DB1.DBW200, this is 200.</param>
|
||||
<returns>The number of read bytes</returns>
|
||||
</member>
|
||||
<member name="M:S7.Net.Plc.ReadClass``1(System.Int32,System.Int32)">
|
||||
<summary>
|
||||
Reads all the bytes needed to fill a class in C#, starting from a certain address, and set all the properties values to the value that are read from the plc.
|
||||
This reads only properties, it doesn't read private variable or public variable without {get;set;} specified. To instantiate the class defined by the generic
|
||||
type, the class needs a default constructor.
|
||||
</summary>
|
||||
<typeparam name="T">The class that will be instantiated. Requires a default constructor</typeparam>
|
||||
<param name="db">Index of the DB; es.: 1 is for DB1</param>
|
||||
<param name="startByteAdr">Start byte address. If you want to read DB1.DBW200, this is 200.</param>
|
||||
<returns>An instance of the class with the values read from the plc. If no data has been read, null will be returned</returns>
|
||||
</member>
|
||||
<member name="M:S7.Net.Plc.ReadClass``1(System.Func{``0},System.Int32,System.Int32)">
|
||||
<summary>
|
||||
Reads all the bytes needed to fill a class in C#, starting from a certain address, and set all the properties values to the value that are read from the plc.
|
||||
This reads only properties, it doesn't read private variable or public variable without {get;set;} specified.
|
||||
</summary>
|
||||
<typeparam name="T">The class that will be instantiated</typeparam>
|
||||
<param name="classFactory">Function to instantiate the class</param>
|
||||
<param name="db">Index of the DB; es.: 1 is for DB1</param>
|
||||
<param name="startByteAdr">Start byte address. If you want to read DB1.DBW200, this is 200.</param>
|
||||
<returns>An instance of the class with the values read from the plc. If no data has been read, null will be returned</returns>
|
||||
</member>
|
||||
<member name="M:S7.Net.Plc.WriteBytes(S7.Net.DataType,System.Int32,System.Int32,System.Byte[])">
|
||||
<summary>
|
||||
Write a number of bytes from a DB starting from a specified index. This handles more than 200 bytes with multiple requests.
|
||||
If the write was not successful, check LastErrorCode or LastErrorString.
|
||||
</summary>
|
||||
<param name="dataType">Data type of the memory area, can be DB, Timer, Counter, Merker(Memory), Input, Output.</param>
|
||||
<param name="db">Address of the memory area (if you want to read DB1, this is set to 1). This must be set also for other memory area types: counters, timers,etc.</param>
|
||||
<param name="startByteAdr">Start byte address. If you want to write DB1.DBW200, this is 200.</param>
|
||||
<param name="value">Bytes to write. If more than 200, multiple requests will be made.</param>
|
||||
<returns>NoError if it was successful, or the error is specified</returns>
|
||||
</member>
|
||||
<member name="M:S7.Net.Plc.WriteBit(S7.Net.DataType,System.Int32,System.Int32,System.Int32,System.Boolean)">
|
||||
<summary>
|
||||
Write a single bit from a DB with the specified index.
|
||||
</summary>
|
||||
<param name="dataType">Data type of the memory area, can be DB, Timer, Counter, Merker(Memory), Input, Output.</param>
|
||||
<param name="db">Address of the memory area (if you want to read DB1, this is set to 1). This must be set also for other memory area types: counters, timers,etc.</param>
|
||||
<param name="startByteAdr">Start byte address. If you want to write DB1.DBW200, this is 200.</param>
|
||||
<param name="bitAdr">The address of the bit. (0-7)</param>
|
||||
<param name="value">Bytes to write. If more than 200, multiple requests will be made.</param>
|
||||
<returns>NoError if it was successful, or the error is specified</returns>
|
||||
</member>
|
||||
<member name="M:S7.Net.Plc.WriteBit(S7.Net.DataType,System.Int32,System.Int32,System.Int32,System.Int32)">
|
||||
<summary>
|
||||
Write a single bit from a DB with the specified index.
|
||||
</summary>
|
||||
<param name="dataType">Data type of the memory area, can be DB, Timer, Counter, Merker(Memory), Input, Output.</param>
|
||||
<param name="db">Address of the memory area (if you want to read DB1, this is set to 1). This must be set also for other memory area types: counters, timers,etc.</param>
|
||||
<param name="startByteAdr">Start byte address. If you want to write DB1.DBW200, this is 200.</param>
|
||||
<param name="bitAdr">The address of the bit. (0-7)</param>
|
||||
<param name="value">Bytes to write. If more than 200, multiple requests will be made.</param>
|
||||
<returns>NoError if it was successful, or the error is specified</returns>
|
||||
</member>
|
||||
<member name="M:S7.Net.Plc.Write(S7.Net.DataType,System.Int32,System.Int32,System.Object,System.Int32)">
|
||||
<summary>
|
||||
Takes in input an object and tries to parse it to an array of values. This can be used to write many data, all of the same type.
|
||||
You must specify the memory area type, memory are address, byte start address and bytes count.
|
||||
If the read was not successful, check LastErrorCode or LastErrorString.
|
||||
</summary>
|
||||
<param name="dataType">Data type of the memory area, can be DB, Timer, Counter, Merker(Memory), Input, Output.</param>
|
||||
<param name="db">Address of the memory area (if you want to read DB1, this is set to 1). This must be set also for other memory area types: counters, timers,etc.</param>
|
||||
<param name="startByteAdr">Start byte address. If you want to read DB1.DBW200, this is 200.</param>
|
||||
<param name="value">Bytes to write. The lenght of this parameter can't be higher than 200. If you need more, use recursion.</param>
|
||||
<param name="bitAdr">The address of the bit. (0-7)</param>
|
||||
<returns>NoError if it was successful, or the error is specified</returns>
|
||||
</member>
|
||||
<member name="M:S7.Net.Plc.Write(System.String,System.Object)">
|
||||
<summary>
|
||||
Writes a single variable from the plc, takes in input strings like "DB1.DBX0.0", "DB20.DBD200", "MB20", "T45", etc.
|
||||
If the write was not successful, check LastErrorCode or LastErrorString.
|
||||
</summary>
|
||||
<param name="variable">Input strings like "DB1.DBX0.0", "DB20.DBD200", "MB20", "T45", etc.</param>
|
||||
<param name="value">Value to be written to the plc</param>
|
||||
<returns>NoError if it was successful, or the error is specified</returns>
|
||||
</member>
|
||||
<member name="M:S7.Net.Plc.WriteStruct(System.Object,System.Int32,System.Int32)">
|
||||
<summary>
|
||||
Writes a C# struct to a DB in the plc
|
||||
</summary>
|
||||
<param name="structValue">The struct to be written</param>
|
||||
<param name="db">Db address</param>
|
||||
<param name="startByteAdr">Start bytes on the plc</param>
|
||||
<returns>NoError if it was successful, or the error is specified</returns>
|
||||
</member>
|
||||
<member name="M:S7.Net.Plc.WriteClass(System.Object,System.Int32,System.Int32)">
|
||||
<summary>
|
||||
Writes a C# class to a DB in the plc
|
||||
</summary>
|
||||
<param name="classValue">The class to be written</param>
|
||||
<param name="db">Db address</param>
|
||||
<param name="startByteAdr">Start bytes on the plc</param>
|
||||
<returns>NoError if it was successful, or the error is specified</returns>
|
||||
</member>
|
||||
<member name="M:S7.Net.Plc.ClearLastError">
|
||||
<summary>
|
||||
Sets the LastErrorCode to NoError and LastErrorString to String.Empty
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:S7.Net.Plc.ReadHeaderPackage(System.Int32)">
|
||||
<summary>
|
||||
Creates the header to read bytes from the plc
|
||||
</summary>
|
||||
<param name="amount"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:S7.Net.Plc.CreateReadDataRequestPackage(S7.Net.DataType,System.Int32,System.Int32,System.Int32)">
|
||||
<summary>
|
||||
Create the bytes-package to request data from the plc. You have to specify the memory type (dataType),
|
||||
the address of the memory, the address of the byte and the bytes count.
|
||||
</summary>
|
||||
<param name="dataType">MemoryType (DB, Timer, Counter, etc.)</param>
|
||||
<param name="db">Address of the memory to be read</param>
|
||||
<param name="startByteAdr">Start address of the byte</param>
|
||||
<param name="count">Number of bytes to be read</param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:S7.Net.Plc.WriteBytesWithASingleRequest(S7.Net.DataType,System.Int32,System.Int32,System.Byte[])">
|
||||
<summary>
|
||||
Writes up to 200 bytes to the plc and returns NoError if successful. You must specify the memory area type, memory are address, byte start address and bytes count.
|
||||
If the write was not successful, check LastErrorCode or LastErrorString.
|
||||
</summary>
|
||||
<param name="dataType">Data type of the memory area, can be DB, Timer, Counter, Merker(Memory), Input, Output.</param>
|
||||
<param name="db">Address of the memory area (if you want to read DB1, this is set to 1). This must be set also for other memory area types: counters, timers,etc.</param>
|
||||
<param name="startByteAdr">Start byte address. If you want to read DB1.DBW200, this is 200.</param>
|
||||
<param name="value">Bytes to write. The lenght of this parameter can't be higher than 200. If you need more, use recursion.</param>
|
||||
<returns>NoError if it was successful, or the error is specified</returns>
|
||||
</member>
|
||||
<member name="M:S7.Net.Plc.ParseBytes(S7.Net.VarType,System.Byte[],System.Int32)">
|
||||
<summary>
|
||||
Given a S7 variable type (Bool, Word, DWord, etc.), it converts the bytes in the appropriate C# format.
|
||||
</summary>
|
||||
<param name="varType"></param>
|
||||
<param name="bytes"></param>
|
||||
<param name="varCount"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:S7.Net.Plc.VarTypeToByteLength(S7.Net.VarType,System.Int32)">
|
||||
<summary>
|
||||
Given a S7 variable type (Bool, Word, DWord, etc.), it returns how many bytes to read.
|
||||
</summary>
|
||||
<param name="varType"></param>
|
||||
<param name="varCount"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:S7.Net.Plc.Dispose">
|
||||
<summary>
|
||||
Releases all resources, disonnects from the plc and closes the socket
|
||||
</summary>
|
||||
</member>
|
||||
<member name="T:S7.Net.Types.Boolean">
|
||||
<summary>
|
||||
Contains the methods to read, set and reset bits inside bytes
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:S7.Net.Types.Boolean.GetValue(System.Byte,System.Int32)">
|
||||
<summary>
|
||||
Returns the value of a bit in a bit, given the address of the bit
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:S7.Net.Types.Boolean.SetBit(System.Byte,System.Int32)">
|
||||
<summary>
|
||||
Sets the value of a bit to 1 (true), given the address of the bit
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:S7.Net.Types.Boolean.ClearBit(System.Byte,System.Int32)">
|
||||
<summary>
|
||||
Resets the value of a bit to 0 (false), given the address of the bit
|
||||
</summary>
|
||||
</member>
|
||||
<member name="T:S7.Net.Types.Byte">
|
||||
<summary>
|
||||
Contains the methods to convert from bytes to byte arrays
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:S7.Net.Types.Byte.ToByteArray(System.Byte)">
|
||||
<summary>
|
||||
Converts a byte to byte array
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:S7.Net.Types.Byte.FromByteArray(System.Byte[])">
|
||||
<summary>
|
||||
Converts a byte array to byte
|
||||
</summary>
|
||||
<param name="bytes"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="T:S7.Net.Types.Class">
|
||||
<summary>
|
||||
Contains the methods to convert a C# class to S7 data types
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:S7.Net.Types.Class.GetClassSize(System.Object)">
|
||||
<summary>
|
||||
Gets the size of the class in bytes.
|
||||
</summary>
|
||||
<param name="instance">An instance of the class</param>
|
||||
<returns>the number of bytes</returns>
|
||||
</member>
|
||||
<member name="M:S7.Net.Types.Class.FromBytes(System.Object,System.Byte[])">
|
||||
<summary>
|
||||
Sets the object's values with the given array of bytes
|
||||
</summary>
|
||||
<param name="sourceClass">The object to fill in the given array of bytes</param>
|
||||
<param name="bytes">The array of bytes</param>
|
||||
</member>
|
||||
<member name="M:S7.Net.Types.Class.ToBytes(System.Object)">
|
||||
<summary>
|
||||
Creates a byte array depending on the struct type.
|
||||
</summary>
|
||||
<param name="sourceClass">The struct object</param>
|
||||
<returns>A byte array or null if fails.</returns>
|
||||
</member>
|
||||
<member name="T:S7.Net.Types.Counter">
|
||||
<summary>
|
||||
Contains the conversion methods to convert Counter from S7 plc to C# ushort (UInt16).
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:S7.Net.Types.Counter.FromByteArray(System.Byte[])">
|
||||
<summary>
|
||||
Converts a Counter (2 bytes) to ushort (UInt16)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:S7.Net.Types.Counter.FromBytes(System.Byte,System.Byte)">
|
||||
<summary>
|
||||
Converts a Counter (2 bytes) to ushort (UInt16)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:S7.Net.Types.Counter.ToByteArray(System.UInt16)">
|
||||
<summary>
|
||||
Converts a ushort (UInt16) to word (2 bytes)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:S7.Net.Types.Counter.ToByteArray(System.UInt16[])">
|
||||
<summary>
|
||||
Converts an array of ushort (UInt16) to an array of bytes
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:S7.Net.Types.Counter.ToArray(System.Byte[])">
|
||||
<summary>
|
||||
Converts an array of bytes to an array of ushort
|
||||
</summary>
|
||||
</member>
|
||||
<member name="T:S7.Net.Types.DataItem">
|
||||
<summary>
|
||||
Create an instance of a memory block that can be read by using ReadMultipleVars
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:S7.Net.Types.DataItem.DataType">
|
||||
<summary>
|
||||
Memory area to read
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:S7.Net.Types.DataItem.VarType">
|
||||
<summary>
|
||||
Type of data to be read (default is bytes)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:S7.Net.Types.DataItem.DB">
|
||||
<summary>
|
||||
Address of memory area to read (example: for DB1 this value is 1, for T45 this value is 45)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:S7.Net.Types.DataItem.StartByteAdr">
|
||||
<summary>
|
||||
Address of the first byte to read
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:S7.Net.Types.DataItem.Count">
|
||||
<summary>
|
||||
Number of variables to read
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:S7.Net.Types.DataItem.Value">
|
||||
<summary>
|
||||
Contains the value of the memory area after the read has been executed
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:S7.Net.Types.DataItem.#ctor">
|
||||
<summary>
|
||||
Create an instance of DataItem
|
||||
</summary>
|
||||
</member>
|
||||
<member name="T:S7.Net.Types.DInt">
|
||||
<summary>
|
||||
Contains the conversion methods to convert DInt from S7 plc to C# int (Int32).
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:S7.Net.Types.DInt.FromByteArray(System.Byte[])">
|
||||
<summary>
|
||||
Converts a S7 DInt (4 bytes) to int (Int32)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:S7.Net.Types.DInt.FromBytes(System.Byte,System.Byte,System.Byte,System.Byte)">
|
||||
<summary>
|
||||
Converts a S7 DInt (4 bytes) to int (Int32)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:S7.Net.Types.DInt.ToByteArray(System.Int32)">
|
||||
<summary>
|
||||
Converts a int (Int32) to S7 DInt (4 bytes)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:S7.Net.Types.DInt.ToByteArray(System.Int32[])">
|
||||
<summary>
|
||||
Converts an array of int (Int32) to an array of bytes
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:S7.Net.Types.DInt.ToArray(System.Byte[])">
|
||||
<summary>
|
||||
Converts an array of S7 DInt to an array of int (Int32)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:S7.Net.Types.DInt.CDWord(System.Int64)">
|
||||
<summary>
|
||||
Converts from C# long (Int64) to C# int (Int32)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="T:S7.Net.Types.Double">
|
||||
<summary>
|
||||
Contains the conversion methods to convert Real from S7 plc to C# double.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:S7.Net.Types.Double.FromByteArray(System.Byte[])">
|
||||
<summary>
|
||||
Converts a S7 Real (4 bytes) to double
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:S7.Net.Types.Double.FromDWord(System.Int32)">
|
||||
<summary>
|
||||
Converts a S7 DInt to double
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:S7.Net.Types.Double.FromDWord(System.UInt32)">
|
||||
<summary>
|
||||
Converts a S7 DWord to double
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:S7.Net.Types.Double.ToByteArray(System.Double)">
|
||||
<summary>
|
||||
Converts a double to S7 Real (4 bytes)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:S7.Net.Types.Double.ToByteArray(System.Double[])">
|
||||
<summary>
|
||||
Converts an array of double to an array of bytes
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:S7.Net.Types.Double.ToArray(System.Byte[])">
|
||||
<summary>
|
||||
Converts an array of S7 Real to an array of double
|
||||
</summary>
|
||||
</member>
|
||||
<member name="T:S7.Net.Types.DWord">
|
||||
<summary>
|
||||
Contains the conversion methods to convert DWord from S7 plc to C#.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:S7.Net.Types.DWord.FromByteArray(System.Byte[])">
|
||||
<summary>
|
||||
Converts a S7 DWord (4 bytes) to uint (UInt32)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:S7.Net.Types.DWord.FromBytes(System.Byte,System.Byte,System.Byte,System.Byte)">
|
||||
<summary>
|
||||
Converts a S7 DWord (4 bytes) to uint (UInt32)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:S7.Net.Types.DWord.ToByteArray(System.UInt32)">
|
||||
<summary>
|
||||
Converts a uint (UInt32) to S7 DWord (4 bytes)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:S7.Net.Types.DWord.ToByteArray(System.UInt32[])">
|
||||
<summary>
|
||||
Converts an array of uint (UInt32) to an array of S7 DWord (4 bytes)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:S7.Net.Types.DWord.ToArray(System.Byte[])">
|
||||
<summary>
|
||||
Converts an array of S7 DWord to an array of uint (UInt32)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="T:S7.Net.Types.Int">
|
||||
<summary>
|
||||
Contains the conversion methods to convert Int from S7 plc to C#.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:S7.Net.Types.Int.FromByteArray(System.Byte[])">
|
||||
<summary>
|
||||
Converts a S7 Int (2 bytes) to short (Int16)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:S7.Net.Types.Int.FromBytes(System.Byte,System.Byte)">
|
||||
<summary>
|
||||
Converts a S7 Int (2 bytes) to short (Int16)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:S7.Net.Types.Int.ToByteArray(System.Int16)">
|
||||
<summary>
|
||||
Converts a short (Int16) to a S7 Int byte array (2 bytes)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:S7.Net.Types.Int.ToByteArray(System.Int16[])">
|
||||
<summary>
|
||||
Converts an array of short (Int16) to a S7 Int byte array (2 bytes)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:S7.Net.Types.Int.ToArray(System.Byte[])">
|
||||
<summary>
|
||||
Converts an array of S7 Int to an array of short (Int16)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:S7.Net.Types.Int.CWord(System.Int32)">
|
||||
<summary>
|
||||
Converts a C# int value to a C# short value, to be used as word.
|
||||
</summary>
|
||||
<param name="value"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="T:S7.Net.Types.String">
|
||||
<summary>
|
||||
Contains the methods to convert from S7 strings to C# strings
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:S7.Net.Types.String.ToByteArray(System.String)">
|
||||
<summary>
|
||||
Converts a string to S7 bytes
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:S7.Net.Types.String.FromByteArray(System.Byte[])">
|
||||
<summary>
|
||||
Converts S7 bytes to a string
|
||||
</summary>
|
||||
<param name="bytes"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="T:S7.Net.Types.Struct">
|
||||
<summary>
|
||||
Contains the method to convert a C# struct to S7 data types
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:S7.Net.Types.Struct.GetStructSize(System.Type)">
|
||||
<summary>
|
||||
Gets the size of the struct in bytes.
|
||||
</summary>
|
||||
<param name="structType">the type of the struct</param>
|
||||
<returns>the number of bytes</returns>
|
||||
</member>
|
||||
<member name="M:S7.Net.Types.Struct.FromBytes(System.Type,System.Byte[])">
|
||||
<summary>
|
||||
Creates a struct of a specified type by an array of bytes.
|
||||
</summary>
|
||||
<param name="structType">The struct type</param>
|
||||
<param name="bytes">The array of bytes</param>
|
||||
<returns>The object depending on the struct type or null if fails(array-length != struct-length</returns>
|
||||
</member>
|
||||
<member name="M:S7.Net.Types.Struct.ToBytes(System.Object)">
|
||||
<summary>
|
||||
Creates a byte array depending on the struct type.
|
||||
</summary>
|
||||
<param name="structValue">The struct object</param>
|
||||
<returns>A byte array or null if fails.</returns>
|
||||
</member>
|
||||
<member name="T:S7.Net.Types.Timer">
|
||||
<summary>
|
||||
Converts the Timer data type to C# data type
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:S7.Net.Types.Timer.FromByteArray(System.Byte[])">
|
||||
<summary>
|
||||
Converts the timer bytes to a double
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:S7.Net.Types.Timer.ToByteArray(System.UInt16)">
|
||||
<summary>
|
||||
Converts a ushort (UInt16) to an array of bytes formatted as time
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:S7.Net.Types.Timer.ToByteArray(System.UInt16[])">
|
||||
<summary>
|
||||
Converts an array of ushorts (Uint16) to an array of bytes formatted as time
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:S7.Net.Types.Timer.ToArray(System.Byte[])">
|
||||
<summary>
|
||||
Converts an array of bytes formatted as time to an array of doubles
|
||||
</summary>
|
||||
<param name="bytes"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="T:S7.Net.Types.Word">
|
||||
<summary>
|
||||
Contains the conversion methods to convert Words from S7 plc to C#.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:S7.Net.Types.Word.FromByteArray(System.Byte[])">
|
||||
<summary>
|
||||
Converts a word (2 bytes) to ushort (UInt16)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:S7.Net.Types.Word.FromBytes(System.Byte,System.Byte)">
|
||||
<summary>
|
||||
Converts a word (2 bytes) to ushort (UInt16)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:S7.Net.Types.Word.ToByteArray(System.UInt16)">
|
||||
<summary>
|
||||
Converts a ushort (UInt16) to word (2 bytes)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:S7.Net.Types.Word.ToByteArray(System.UInt16[])">
|
||||
<summary>
|
||||
Converts an array of ushort (UInt16) to an array of bytes
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:S7.Net.Types.Word.ToArray(System.Byte[])">
|
||||
<summary>
|
||||
Converts an array of bytes to an array of ushort
|
||||
</summary>
|
||||
</member>
|
||||
</members>
|
||||
</doc>
|
||||
Binary file not shown.
@@ -1,917 +0,0 @@
|
||||
<?xml version="1.0"?>
|
||||
<doc>
|
||||
<assembly>
|
||||
<name>S7.Net</name>
|
||||
</assembly>
|
||||
<members>
|
||||
<member name="T:S7.Net.Conversion">
|
||||
<summary>
|
||||
Conversion methods to convert from Siemens numeric format to C# and back
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:S7.Net.Conversion.BinStringToInt32(System.String)">
|
||||
<summary>
|
||||
Converts a binary string to Int32 value
|
||||
</summary>
|
||||
<param name="txt"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:S7.Net.Conversion.BinStringToByte(System.String)">
|
||||
<summary>
|
||||
Converts a binary string to a byte. Can return null.
|
||||
</summary>
|
||||
<param name="txt"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:S7.Net.Conversion.ValToBinString(System.Object)">
|
||||
<summary>
|
||||
Converts the value to a binary string
|
||||
</summary>
|
||||
<param name="value"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:S7.Net.Conversion.SelectBit(System.Byte,System.Int32)">
|
||||
<summary>
|
||||
Helper to get a bit value given a byte and the bit index.
|
||||
Example: DB1.DBX0.5 -> var bytes = ReadBytes(DB1.DBW0); bool bit = bytes[0].SelectBit(5);
|
||||
</summary>
|
||||
<param name="data"></param>
|
||||
<param name="bitPosition"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:S7.Net.Conversion.ConvertToShort(System.UInt16)">
|
||||
<summary>
|
||||
Converts from ushort value to short value; it's used to retrieve negative values from words
|
||||
</summary>
|
||||
<param name="input"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:S7.Net.Conversion.ConvertToUshort(System.Int16)">
|
||||
<summary>
|
||||
Converts from short value to ushort value; it's used to pass negative values to DWs
|
||||
</summary>
|
||||
<param name="input"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:S7.Net.Conversion.ConvertToInt(System.UInt32)">
|
||||
<summary>
|
||||
Converts from UInt32 value to Int32 value; it's used to retrieve negative values from DBDs
|
||||
</summary>
|
||||
<param name="input"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:S7.Net.Conversion.ConvertToUInt(System.Int32)">
|
||||
<summary>
|
||||
Converts from Int32 value to UInt32 value; it's used to pass negative values to DBDs
|
||||
</summary>
|
||||
<param name="input"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:S7.Net.Conversion.ConvertToUInt(System.Double)">
|
||||
<summary>
|
||||
Converts from double to DWord (DBD)
|
||||
</summary>
|
||||
<param name="input"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:S7.Net.Conversion.ConvertToDouble(System.UInt32)">
|
||||
<summary>
|
||||
Converts from DWord (DBD) to double
|
||||
</summary>
|
||||
<param name="input"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="T:S7.Net.CpuType">
|
||||
<summary>
|
||||
Types of S7 cpu supported by the library
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:S7.Net.CpuType.S7200">
|
||||
<summary>
|
||||
S7 200 cpu type
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:S7.Net.CpuType.S7300">
|
||||
<summary>
|
||||
S7 300 cpu type
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:S7.Net.CpuType.S7400">
|
||||
<summary>
|
||||
S7 400 cpu type
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:S7.Net.CpuType.S71200">
|
||||
<summary>
|
||||
S7 1200 cpu type
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:S7.Net.CpuType.S71500">
|
||||
<summary>
|
||||
S7 1500 cpu type
|
||||
</summary>
|
||||
</member>
|
||||
<member name="T:S7.Net.ErrorCode">
|
||||
<summary>
|
||||
Types of error code that can be set after a function is called
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:S7.Net.ErrorCode.NoError">
|
||||
<summary>
|
||||
The function has been executed correctly
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:S7.Net.ErrorCode.WrongCPU_Type">
|
||||
<summary>
|
||||
Wrong type of CPU error
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:S7.Net.ErrorCode.ConnectionError">
|
||||
<summary>
|
||||
Connection error
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:S7.Net.ErrorCode.IPAddressNotAvailable">
|
||||
<summary>
|
||||
Ip address not available
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:S7.Net.ErrorCode.WrongVarFormat">
|
||||
<summary>
|
||||
Wrong format of the variable
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:S7.Net.ErrorCode.WrongNumberReceivedBytes">
|
||||
<summary>
|
||||
Wrong number of received bytes
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:S7.Net.ErrorCode.SendData">
|
||||
<summary>
|
||||
Error on send data
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:S7.Net.ErrorCode.ReadData">
|
||||
<summary>
|
||||
Error on read data
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:S7.Net.ErrorCode.WriteData">
|
||||
<summary>
|
||||
Error on write data
|
||||
</summary>
|
||||
</member>
|
||||
<member name="T:S7.Net.DataType">
|
||||
<summary>
|
||||
Types of memory area that can be read
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:S7.Net.DataType.Input">
|
||||
<summary>
|
||||
Input area memory
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:S7.Net.DataType.Output">
|
||||
<summary>
|
||||
Output area memory
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:S7.Net.DataType.Memory">
|
||||
<summary>
|
||||
Merkers area memory (M0, M0.0, ...)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:S7.Net.DataType.DataBlock">
|
||||
<summary>
|
||||
DB area memory (DB1, DB2, ...)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:S7.Net.DataType.Timer">
|
||||
<summary>
|
||||
Timer area memory(T1, T2, ...)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:S7.Net.DataType.Counter">
|
||||
<summary>
|
||||
Counter area memory (C1, C2, ...)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="T:S7.Net.VarType">
|
||||
<summary>
|
||||
Types
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:S7.Net.VarType.Bit">
|
||||
<summary>
|
||||
S7 Bit variable type (bool)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:S7.Net.VarType.Byte">
|
||||
<summary>
|
||||
S7 Byte variable type (8 bits)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:S7.Net.VarType.Word">
|
||||
<summary>
|
||||
S7 Word variable type (16 bits, 2 bytes)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:S7.Net.VarType.DWord">
|
||||
<summary>
|
||||
S7 DWord variable type (32 bits, 4 bytes)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:S7.Net.VarType.Int">
|
||||
<summary>
|
||||
S7 Int variable type (16 bits, 2 bytes)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:S7.Net.VarType.DInt">
|
||||
<summary>
|
||||
DInt variable type (32 bits, 4 bytes)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:S7.Net.VarType.Real">
|
||||
<summary>
|
||||
Real variable type (32 bits, 4 bytes)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:S7.Net.VarType.String">
|
||||
<summary>
|
||||
String variable type (variable)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:S7.Net.VarType.Timer">
|
||||
<summary>
|
||||
Timer variable type
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:S7.Net.VarType.Counter">
|
||||
<summary>
|
||||
Counter variable type
|
||||
</summary>
|
||||
</member>
|
||||
<member name="T:S7.Net.Plc">
|
||||
<summary>
|
||||
Creates an instance of S7.Net driver
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:S7.Net.Plc.IP">
|
||||
<summary>
|
||||
Ip address of the plc
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:S7.Net.Plc.CPU">
|
||||
<summary>
|
||||
Cpu type of the plc
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:S7.Net.Plc.Rack">
|
||||
<summary>
|
||||
Rack of the plc
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:S7.Net.Plc.Slot">
|
||||
<summary>
|
||||
Slot of the CPU of the plc
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:S7.Net.Plc.IsAvailable">
|
||||
<summary>
|
||||
Returns true if a connection to the plc can be established
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:S7.Net.Plc.IsConnected">
|
||||
<summary>
|
||||
Checks if the socket is connected and polls the other peer (the plc) to see if it's connected.
|
||||
This is the variable that you should continously check to see if the communication is working
|
||||
See also: http://stackoverflow.com/questions/2661764/how-to-check-if-a-socket-is-connected-disconnected-in-c
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:S7.Net.Plc.LastErrorString">
|
||||
<summary>
|
||||
Contains the last error registered when executing a function
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:S7.Net.Plc.LastErrorCode">
|
||||
<summary>
|
||||
Contains the last error code registered when executing a function
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:S7.Net.Plc.#ctor(S7.Net.CpuType,System.String,System.Int16,System.Int16)">
|
||||
<summary>
|
||||
Creates a PLC object with all the parameters needed for connections.
|
||||
For S7-1200 and S7-1500, the default is rack = 0 and slot = 0.
|
||||
You need slot > 0 if you are connecting to external ethernet card (CP).
|
||||
For S7-300 and S7-400 the default is rack = 0 and slot = 2.
|
||||
</summary>
|
||||
<param name="cpu">CpuType of the plc (select from the enum)</param>
|
||||
<param name="ip">Ip address of the plc</param>
|
||||
<param name="rack">rack of the plc, usually it's 0, but check in the hardware configuration of Step7 or TIA portal</param>
|
||||
<param name="slot">slot of the CPU of the plc, usually it's 2 for S7300-S7400, 0 for S7-1200 and S7-1500.
|
||||
If you use an external ethernet card, this must be set accordingly.</param>
|
||||
</member>
|
||||
<member name="M:S7.Net.Plc.Open">
|
||||
<summary>
|
||||
Open a socket and connects to the plc, sending all the corrected package and returning if the connection was successful (ErroreCode.NoError) of it was wrong.
|
||||
</summary>
|
||||
<returns>Returns ErrorCode.NoError if the connection was successful, otherwise check the ErrorCode</returns>
|
||||
</member>
|
||||
<member name="M:S7.Net.Plc.Close">
|
||||
<summary>
|
||||
Disonnects from the plc and close the socket
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:S7.Net.Plc.ReadMultipleVars(System.Collections.Generic.List{S7.Net.Types.DataItem})">
|
||||
<summary>
|
||||
Reads multiple vars in a single request.
|
||||
You have to create and pass a list of DataItems and you obtain in response the same list with the values.
|
||||
Values are stored in the property "Value" of the dataItem and are already converted.
|
||||
If you don't want the conversion, just create a dataItem of bytes.
|
||||
DataItems must not be more than 20 (protocol restriction) and bytes must not be more than 200 + 22 of header (protocol restriction).
|
||||
</summary>
|
||||
<param name="dataItems">List of dataitems that contains the list of variables that must be read. Maximum 20 dataitems are accepted.</param>
|
||||
</member>
|
||||
<member name="M:S7.Net.Plc.ReadBytes(S7.Net.DataType,System.Int32,System.Int32,System.Int32)">
|
||||
<summary>
|
||||
Reads a number of bytes from a DB starting from a specified index. This handles more than 200 bytes with multiple requests.
|
||||
If the read was not successful, check LastErrorCode or LastErrorString.
|
||||
</summary>
|
||||
<param name="dataType">Data type of the memory area, can be DB, Timer, Counter, Merker(Memory), Input, Output.</param>
|
||||
<param name="db">Address of the memory area (if you want to read DB1, this is set to 1). This must be set also for other memory area types: counters, timers,etc.</param>
|
||||
<param name="startByteAdr">Start byte address. If you want to read DB1.DBW200, this is 200.</param>
|
||||
<param name="count">Byte count, if you want to read 120 bytes, set this to 120.</param>
|
||||
<returns>Returns the bytes in an array</returns>
|
||||
</member>
|
||||
<member name="M:S7.Net.Plc.Read(S7.Net.DataType,System.Int32,System.Int32,S7.Net.VarType,System.Int32)">
|
||||
<summary>
|
||||
Read and decode a certain number of bytes of the "VarType" provided.
|
||||
This can be used to read multiple consecutive variables of the same type (Word, DWord, Int, etc).
|
||||
If the read was not successful, check LastErrorCode or LastErrorString.
|
||||
</summary>
|
||||
<param name="dataType">Data type of the memory area, can be DB, Timer, Counter, Merker(Memory), Input, Output.</param>
|
||||
<param name="db">Address of the memory area (if you want to read DB1, this is set to 1). This must be set also for other memory area types: counters, timers,etc.</param>
|
||||
<param name="startByteAdr">Start byte address. If you want to read DB1.DBW200, this is 200.</param>
|
||||
<param name="varType">Type of the variable/s that you are reading</param>
|
||||
<param name="varCount"></param>
|
||||
</member>
|
||||
<member name="M:S7.Net.Plc.Read(System.String)">
|
||||
<summary>
|
||||
Reads a single variable from the plc, takes in input strings like "DB1.DBX0.0", "DB20.DBD200", "MB20", "T45", etc.
|
||||
If the read was not successful, check LastErrorCode or LastErrorString.
|
||||
</summary>
|
||||
<param name="variable">Input strings like "DB1.DBX0.0", "DB20.DBD200", "MB20", "T45", etc.</param>
|
||||
<returns>Returns an object that contains the value. This object must be cast accordingly.</returns>
|
||||
</member>
|
||||
<member name="M:S7.Net.Plc.ReadStruct(System.Type,System.Int32,System.Int32)">
|
||||
<summary>
|
||||
Reads all the bytes needed to fill a struct in C#, starting from a certain address, and return an object that can be casted to the struct.
|
||||
</summary>
|
||||
<param name="structType">Type of the struct to be readed (es.: TypeOf(MyStruct)).</param>
|
||||
<param name="db">Address of the DB.</param>
|
||||
<param name="startByteAdr">Start byte address. If you want to read DB1.DBW200, this is 200.</param>
|
||||
<returns>Returns a struct that must be cast.</returns>
|
||||
</member>
|
||||
<member name="M:S7.Net.Plc.ReadStruct``1(System.Int32,System.Int32)">
|
||||
<summary>
|
||||
Reads all the bytes needed to fill a struct in C#, starting from a certain address, and returns the struct or null if nothing was read.
|
||||
</summary>
|
||||
<typeparam name="T">The struct type</typeparam>
|
||||
<param name="db">Address of the DB.</param>
|
||||
<param name="startByteAdr">Start byte address. If you want to read DB1.DBW200, this is 200.</param>
|
||||
<returns>Returns a nulable struct. If nothing was read null will be returned.</returns>
|
||||
</member>
|
||||
<member name="M:S7.Net.Plc.ReadClass(System.Object,System.Int32,System.Int32)">
|
||||
<summary>
|
||||
Reads all the bytes needed to fill a class in C#, starting from a certain address, and set all the properties values to the value that are read from the plc.
|
||||
This reads only properties, it doesn't read private variable or public variable without {get;set;} specified.
|
||||
</summary>
|
||||
<param name="sourceClass">Instance of the class that will store the values</param>
|
||||
<param name="db">Index of the DB; es.: 1 is for DB1</param>
|
||||
<param name="startByteAdr">Start byte address. If you want to read DB1.DBW200, this is 200.</param>
|
||||
<returns>The number of read bytes</returns>
|
||||
</member>
|
||||
<member name="M:S7.Net.Plc.ReadClass``1(System.Int32,System.Int32)">
|
||||
<summary>
|
||||
Reads all the bytes needed to fill a class in C#, starting from a certain address, and set all the properties values to the value that are read from the plc.
|
||||
This reads only properties, it doesn't read private variable or public variable without {get;set;} specified. To instantiate the class defined by the generic
|
||||
type, the class needs a default constructor.
|
||||
</summary>
|
||||
<typeparam name="T">The class that will be instantiated. Requires a default constructor</typeparam>
|
||||
<param name="db">Index of the DB; es.: 1 is for DB1</param>
|
||||
<param name="startByteAdr">Start byte address. If you want to read DB1.DBW200, this is 200.</param>
|
||||
<returns>An instance of the class with the values read from the plc. If no data has been read, null will be returned</returns>
|
||||
</member>
|
||||
<member name="M:S7.Net.Plc.ReadClass``1(System.Func{``0},System.Int32,System.Int32)">
|
||||
<summary>
|
||||
Reads all the bytes needed to fill a class in C#, starting from a certain address, and set all the properties values to the value that are read from the plc.
|
||||
This reads only properties, it doesn't read private variable or public variable without {get;set;} specified.
|
||||
</summary>
|
||||
<typeparam name="T">The class that will be instantiated</typeparam>
|
||||
<param name="classFactory">Function to instantiate the class</param>
|
||||
<param name="db">Index of the DB; es.: 1 is for DB1</param>
|
||||
<param name="startByteAdr">Start byte address. If you want to read DB1.DBW200, this is 200.</param>
|
||||
<returns>An instance of the class with the values read from the plc. If no data has been read, null will be returned</returns>
|
||||
</member>
|
||||
<member name="M:S7.Net.Plc.WriteBytes(S7.Net.DataType,System.Int32,System.Int32,System.Byte[])">
|
||||
<summary>
|
||||
Write a number of bytes from a DB starting from a specified index. This handles more than 200 bytes with multiple requests.
|
||||
If the write was not successful, check LastErrorCode or LastErrorString.
|
||||
</summary>
|
||||
<param name="dataType">Data type of the memory area, can be DB, Timer, Counter, Merker(Memory), Input, Output.</param>
|
||||
<param name="db">Address of the memory area (if you want to read DB1, this is set to 1). This must be set also for other memory area types: counters, timers,etc.</param>
|
||||
<param name="startByteAdr">Start byte address. If you want to write DB1.DBW200, this is 200.</param>
|
||||
<param name="value">Bytes to write. If more than 200, multiple requests will be made.</param>
|
||||
<returns>NoError if it was successful, or the error is specified</returns>
|
||||
</member>
|
||||
<member name="M:S7.Net.Plc.WriteBit(S7.Net.DataType,System.Int32,System.Int32,System.Int32,System.Boolean)">
|
||||
<summary>
|
||||
Write a single bit from a DB with the specified index.
|
||||
</summary>
|
||||
<param name="dataType">Data type of the memory area, can be DB, Timer, Counter, Merker(Memory), Input, Output.</param>
|
||||
<param name="db">Address of the memory area (if you want to read DB1, this is set to 1). This must be set also for other memory area types: counters, timers,etc.</param>
|
||||
<param name="startByteAdr">Start byte address. If you want to write DB1.DBW200, this is 200.</param>
|
||||
<param name="bitAdr">The address of the bit. (0-7)</param>
|
||||
<param name="value">Bytes to write. If more than 200, multiple requests will be made.</param>
|
||||
<returns>NoError if it was successful, or the error is specified</returns>
|
||||
</member>
|
||||
<member name="M:S7.Net.Plc.WriteBit(S7.Net.DataType,System.Int32,System.Int32,System.Int32,System.Int32)">
|
||||
<summary>
|
||||
Write a single bit from a DB with the specified index.
|
||||
</summary>
|
||||
<param name="dataType">Data type of the memory area, can be DB, Timer, Counter, Merker(Memory), Input, Output.</param>
|
||||
<param name="db">Address of the memory area (if you want to read DB1, this is set to 1). This must be set also for other memory area types: counters, timers,etc.</param>
|
||||
<param name="startByteAdr">Start byte address. If you want to write DB1.DBW200, this is 200.</param>
|
||||
<param name="bitAdr">The address of the bit. (0-7)</param>
|
||||
<param name="value">Bytes to write. If more than 200, multiple requests will be made.</param>
|
||||
<returns>NoError if it was successful, or the error is specified</returns>
|
||||
</member>
|
||||
<member name="M:S7.Net.Plc.Write(S7.Net.DataType,System.Int32,System.Int32,System.Object,System.Int32)">
|
||||
<summary>
|
||||
Takes in input an object and tries to parse it to an array of values. This can be used to write many data, all of the same type.
|
||||
You must specify the memory area type, memory are address, byte start address and bytes count.
|
||||
If the read was not successful, check LastErrorCode or LastErrorString.
|
||||
</summary>
|
||||
<param name="dataType">Data type of the memory area, can be DB, Timer, Counter, Merker(Memory), Input, Output.</param>
|
||||
<param name="db">Address of the memory area (if you want to read DB1, this is set to 1). This must be set also for other memory area types: counters, timers,etc.</param>
|
||||
<param name="startByteAdr">Start byte address. If you want to read DB1.DBW200, this is 200.</param>
|
||||
<param name="value">Bytes to write. The lenght of this parameter can't be higher than 200. If you need more, use recursion.</param>
|
||||
<param name="bitAdr">The address of the bit. (0-7)</param>
|
||||
<returns>NoError if it was successful, or the error is specified</returns>
|
||||
</member>
|
||||
<member name="M:S7.Net.Plc.Write(System.String,System.Object)">
|
||||
<summary>
|
||||
Writes a single variable from the plc, takes in input strings like "DB1.DBX0.0", "DB20.DBD200", "MB20", "T45", etc.
|
||||
If the write was not successful, check LastErrorCode or LastErrorString.
|
||||
</summary>
|
||||
<param name="variable">Input strings like "DB1.DBX0.0", "DB20.DBD200", "MB20", "T45", etc.</param>
|
||||
<param name="value">Value to be written to the plc</param>
|
||||
<returns>NoError if it was successful, or the error is specified</returns>
|
||||
</member>
|
||||
<member name="M:S7.Net.Plc.WriteStruct(System.Object,System.Int32,System.Int32)">
|
||||
<summary>
|
||||
Writes a C# struct to a DB in the plc
|
||||
</summary>
|
||||
<param name="structValue">The struct to be written</param>
|
||||
<param name="db">Db address</param>
|
||||
<param name="startByteAdr">Start bytes on the plc</param>
|
||||
<returns>NoError if it was successful, or the error is specified</returns>
|
||||
</member>
|
||||
<member name="M:S7.Net.Plc.WriteClass(System.Object,System.Int32,System.Int32)">
|
||||
<summary>
|
||||
Writes a C# class to a DB in the plc
|
||||
</summary>
|
||||
<param name="classValue">The class to be written</param>
|
||||
<param name="db">Db address</param>
|
||||
<param name="startByteAdr">Start bytes on the plc</param>
|
||||
<returns>NoError if it was successful, or the error is specified</returns>
|
||||
</member>
|
||||
<member name="M:S7.Net.Plc.ClearLastError">
|
||||
<summary>
|
||||
Sets the LastErrorCode to NoError and LastErrorString to String.Empty
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:S7.Net.Plc.ReadHeaderPackage(System.Int32)">
|
||||
<summary>
|
||||
Creates the header to read bytes from the plc
|
||||
</summary>
|
||||
<param name="amount"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:S7.Net.Plc.CreateReadDataRequestPackage(S7.Net.DataType,System.Int32,System.Int32,System.Int32)">
|
||||
<summary>
|
||||
Create the bytes-package to request data from the plc. You have to specify the memory type (dataType),
|
||||
the address of the memory, the address of the byte and the bytes count.
|
||||
</summary>
|
||||
<param name="dataType">MemoryType (DB, Timer, Counter, etc.)</param>
|
||||
<param name="db">Address of the memory to be read</param>
|
||||
<param name="startByteAdr">Start address of the byte</param>
|
||||
<param name="count">Number of bytes to be read</param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:S7.Net.Plc.WriteBytesWithASingleRequest(S7.Net.DataType,System.Int32,System.Int32,System.Byte[])">
|
||||
<summary>
|
||||
Writes up to 200 bytes to the plc and returns NoError if successful. You must specify the memory area type, memory are address, byte start address and bytes count.
|
||||
If the write was not successful, check LastErrorCode or LastErrorString.
|
||||
</summary>
|
||||
<param name="dataType">Data type of the memory area, can be DB, Timer, Counter, Merker(Memory), Input, Output.</param>
|
||||
<param name="db">Address of the memory area (if you want to read DB1, this is set to 1). This must be set also for other memory area types: counters, timers,etc.</param>
|
||||
<param name="startByteAdr">Start byte address. If you want to read DB1.DBW200, this is 200.</param>
|
||||
<param name="value">Bytes to write. The lenght of this parameter can't be higher than 200. If you need more, use recursion.</param>
|
||||
<returns>NoError if it was successful, or the error is specified</returns>
|
||||
</member>
|
||||
<member name="M:S7.Net.Plc.ParseBytes(S7.Net.VarType,System.Byte[],System.Int32)">
|
||||
<summary>
|
||||
Given a S7 variable type (Bool, Word, DWord, etc.), it converts the bytes in the appropriate C# format.
|
||||
</summary>
|
||||
<param name="varType"></param>
|
||||
<param name="bytes"></param>
|
||||
<param name="varCount"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:S7.Net.Plc.VarTypeToByteLength(S7.Net.VarType,System.Int32)">
|
||||
<summary>
|
||||
Given a S7 variable type (Bool, Word, DWord, etc.), it returns how many bytes to read.
|
||||
</summary>
|
||||
<param name="varType"></param>
|
||||
<param name="varCount"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:S7.Net.Plc.Dispose">
|
||||
<summary>
|
||||
Releases all resources, disonnects from the plc and closes the socket
|
||||
</summary>
|
||||
</member>
|
||||
<member name="T:S7.Net.Types.Boolean">
|
||||
<summary>
|
||||
Contains the methods to read, set and reset bits inside bytes
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:S7.Net.Types.Boolean.GetValue(System.Byte,System.Int32)">
|
||||
<summary>
|
||||
Returns the value of a bit in a bit, given the address of the bit
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:S7.Net.Types.Boolean.SetBit(System.Byte,System.Int32)">
|
||||
<summary>
|
||||
Sets the value of a bit to 1 (true), given the address of the bit
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:S7.Net.Types.Boolean.ClearBit(System.Byte,System.Int32)">
|
||||
<summary>
|
||||
Resets the value of a bit to 0 (false), given the address of the bit
|
||||
</summary>
|
||||
</member>
|
||||
<member name="T:S7.Net.Types.Byte">
|
||||
<summary>
|
||||
Contains the methods to convert from bytes to byte arrays
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:S7.Net.Types.Byte.ToByteArray(System.Byte)">
|
||||
<summary>
|
||||
Converts a byte to byte array
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:S7.Net.Types.Byte.FromByteArray(System.Byte[])">
|
||||
<summary>
|
||||
Converts a byte array to byte
|
||||
</summary>
|
||||
<param name="bytes"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="T:S7.Net.Types.Class">
|
||||
<summary>
|
||||
Contains the methods to convert a C# class to S7 data types
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:S7.Net.Types.Class.GetClassSize(System.Object)">
|
||||
<summary>
|
||||
Gets the size of the class in bytes.
|
||||
</summary>
|
||||
<param name="instance">An instance of the class</param>
|
||||
<returns>the number of bytes</returns>
|
||||
</member>
|
||||
<member name="M:S7.Net.Types.Class.FromBytes(System.Object,System.Byte[])">
|
||||
<summary>
|
||||
Sets the object's values with the given array of bytes
|
||||
</summary>
|
||||
<param name="sourceClass">The object to fill in the given array of bytes</param>
|
||||
<param name="bytes">The array of bytes</param>
|
||||
</member>
|
||||
<member name="M:S7.Net.Types.Class.ToBytes(System.Object)">
|
||||
<summary>
|
||||
Creates a byte array depending on the struct type.
|
||||
</summary>
|
||||
<param name="sourceClass">The struct object</param>
|
||||
<returns>A byte array or null if fails.</returns>
|
||||
</member>
|
||||
<member name="T:S7.Net.Types.Counter">
|
||||
<summary>
|
||||
Contains the conversion methods to convert Counter from S7 plc to C# ushort (UInt16).
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:S7.Net.Types.Counter.FromByteArray(System.Byte[])">
|
||||
<summary>
|
||||
Converts a Counter (2 bytes) to ushort (UInt16)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:S7.Net.Types.Counter.FromBytes(System.Byte,System.Byte)">
|
||||
<summary>
|
||||
Converts a Counter (2 bytes) to ushort (UInt16)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:S7.Net.Types.Counter.ToByteArray(System.UInt16)">
|
||||
<summary>
|
||||
Converts a ushort (UInt16) to word (2 bytes)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:S7.Net.Types.Counter.ToByteArray(System.UInt16[])">
|
||||
<summary>
|
||||
Converts an array of ushort (UInt16) to an array of bytes
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:S7.Net.Types.Counter.ToArray(System.Byte[])">
|
||||
<summary>
|
||||
Converts an array of bytes to an array of ushort
|
||||
</summary>
|
||||
</member>
|
||||
<member name="T:S7.Net.Types.DataItem">
|
||||
<summary>
|
||||
Create an instance of a memory block that can be read by using ReadMultipleVars
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:S7.Net.Types.DataItem.DataType">
|
||||
<summary>
|
||||
Memory area to read
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:S7.Net.Types.DataItem.VarType">
|
||||
<summary>
|
||||
Type of data to be read (default is bytes)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:S7.Net.Types.DataItem.DB">
|
||||
<summary>
|
||||
Address of memory area to read (example: for DB1 this value is 1, for T45 this value is 45)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:S7.Net.Types.DataItem.StartByteAdr">
|
||||
<summary>
|
||||
Address of the first byte to read
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:S7.Net.Types.DataItem.Count">
|
||||
<summary>
|
||||
Number of variables to read
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:S7.Net.Types.DataItem.Value">
|
||||
<summary>
|
||||
Contains the value of the memory area after the read has been executed
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:S7.Net.Types.DataItem.#ctor">
|
||||
<summary>
|
||||
Create an instance of DataItem
|
||||
</summary>
|
||||
</member>
|
||||
<member name="T:S7.Net.Types.DInt">
|
||||
<summary>
|
||||
Contains the conversion methods to convert DInt from S7 plc to C# int (Int32).
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:S7.Net.Types.DInt.FromByteArray(System.Byte[])">
|
||||
<summary>
|
||||
Converts a S7 DInt (4 bytes) to int (Int32)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:S7.Net.Types.DInt.FromBytes(System.Byte,System.Byte,System.Byte,System.Byte)">
|
||||
<summary>
|
||||
Converts a S7 DInt (4 bytes) to int (Int32)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:S7.Net.Types.DInt.ToByteArray(System.Int32)">
|
||||
<summary>
|
||||
Converts a int (Int32) to S7 DInt (4 bytes)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:S7.Net.Types.DInt.ToByteArray(System.Int32[])">
|
||||
<summary>
|
||||
Converts an array of int (Int32) to an array of bytes
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:S7.Net.Types.DInt.ToArray(System.Byte[])">
|
||||
<summary>
|
||||
Converts an array of S7 DInt to an array of int (Int32)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:S7.Net.Types.DInt.CDWord(System.Int64)">
|
||||
<summary>
|
||||
Converts from C# long (Int64) to C# int (Int32)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="T:S7.Net.Types.Double">
|
||||
<summary>
|
||||
Contains the conversion methods to convert Real from S7 plc to C# double.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:S7.Net.Types.Double.FromByteArray(System.Byte[])">
|
||||
<summary>
|
||||
Converts a S7 Real (4 bytes) to double
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:S7.Net.Types.Double.FromDWord(System.Int32)">
|
||||
<summary>
|
||||
Converts a S7 DInt to double
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:S7.Net.Types.Double.FromDWord(System.UInt32)">
|
||||
<summary>
|
||||
Converts a S7 DWord to double
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:S7.Net.Types.Double.ToByteArray(System.Double)">
|
||||
<summary>
|
||||
Converts a double to S7 Real (4 bytes)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:S7.Net.Types.Double.ToByteArray(System.Double[])">
|
||||
<summary>
|
||||
Converts an array of double to an array of bytes
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:S7.Net.Types.Double.ToArray(System.Byte[])">
|
||||
<summary>
|
||||
Converts an array of S7 Real to an array of double
|
||||
</summary>
|
||||
</member>
|
||||
<member name="T:S7.Net.Types.DWord">
|
||||
<summary>
|
||||
Contains the conversion methods to convert DWord from S7 plc to C#.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:S7.Net.Types.DWord.FromByteArray(System.Byte[])">
|
||||
<summary>
|
||||
Converts a S7 DWord (4 bytes) to uint (UInt32)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:S7.Net.Types.DWord.FromBytes(System.Byte,System.Byte,System.Byte,System.Byte)">
|
||||
<summary>
|
||||
Converts a S7 DWord (4 bytes) to uint (UInt32)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:S7.Net.Types.DWord.ToByteArray(System.UInt32)">
|
||||
<summary>
|
||||
Converts a uint (UInt32) to S7 DWord (4 bytes)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:S7.Net.Types.DWord.ToByteArray(System.UInt32[])">
|
||||
<summary>
|
||||
Converts an array of uint (UInt32) to an array of S7 DWord (4 bytes)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:S7.Net.Types.DWord.ToArray(System.Byte[])">
|
||||
<summary>
|
||||
Converts an array of S7 DWord to an array of uint (UInt32)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="T:S7.Net.Types.Int">
|
||||
<summary>
|
||||
Contains the conversion methods to convert Int from S7 plc to C#.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:S7.Net.Types.Int.FromByteArray(System.Byte[])">
|
||||
<summary>
|
||||
Converts a S7 Int (2 bytes) to short (Int16)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:S7.Net.Types.Int.FromBytes(System.Byte,System.Byte)">
|
||||
<summary>
|
||||
Converts a S7 Int (2 bytes) to short (Int16)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:S7.Net.Types.Int.ToByteArray(System.Int16)">
|
||||
<summary>
|
||||
Converts a short (Int16) to a S7 Int byte array (2 bytes)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:S7.Net.Types.Int.ToByteArray(System.Int16[])">
|
||||
<summary>
|
||||
Converts an array of short (Int16) to a S7 Int byte array (2 bytes)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:S7.Net.Types.Int.ToArray(System.Byte[])">
|
||||
<summary>
|
||||
Converts an array of S7 Int to an array of short (Int16)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:S7.Net.Types.Int.CWord(System.Int32)">
|
||||
<summary>
|
||||
Converts a C# int value to a C# short value, to be used as word.
|
||||
</summary>
|
||||
<param name="value"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="T:S7.Net.Types.String">
|
||||
<summary>
|
||||
Contains the methods to convert from S7 strings to C# strings
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:S7.Net.Types.String.ToByteArray(System.String)">
|
||||
<summary>
|
||||
Converts a string to S7 bytes
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:S7.Net.Types.String.FromByteArray(System.Byte[])">
|
||||
<summary>
|
||||
Converts S7 bytes to a string
|
||||
</summary>
|
||||
<param name="bytes"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="T:S7.Net.Types.Struct">
|
||||
<summary>
|
||||
Contains the method to convert a C# struct to S7 data types
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:S7.Net.Types.Struct.GetStructSize(System.Type)">
|
||||
<summary>
|
||||
Gets the size of the struct in bytes.
|
||||
</summary>
|
||||
<param name="structType">the type of the struct</param>
|
||||
<returns>the number of bytes</returns>
|
||||
</member>
|
||||
<member name="M:S7.Net.Types.Struct.FromBytes(System.Type,System.Byte[])">
|
||||
<summary>
|
||||
Creates a struct of a specified type by an array of bytes.
|
||||
</summary>
|
||||
<param name="structType">The struct type</param>
|
||||
<param name="bytes">The array of bytes</param>
|
||||
<returns>The object depending on the struct type or null if fails(array-length != struct-length</returns>
|
||||
</member>
|
||||
<member name="M:S7.Net.Types.Struct.ToBytes(System.Object)">
|
||||
<summary>
|
||||
Creates a byte array depending on the struct type.
|
||||
</summary>
|
||||
<param name="structValue">The struct object</param>
|
||||
<returns>A byte array or null if fails.</returns>
|
||||
</member>
|
||||
<member name="T:S7.Net.Types.Timer">
|
||||
<summary>
|
||||
Converts the Timer data type to C# data type
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:S7.Net.Types.Timer.FromByteArray(System.Byte[])">
|
||||
<summary>
|
||||
Converts the timer bytes to a double
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:S7.Net.Types.Timer.ToByteArray(System.UInt16)">
|
||||
<summary>
|
||||
Converts a ushort (UInt16) to an array of bytes formatted as time
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:S7.Net.Types.Timer.ToByteArray(System.UInt16[])">
|
||||
<summary>
|
||||
Converts an array of ushorts (Uint16) to an array of bytes formatted as time
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:S7.Net.Types.Timer.ToArray(System.Byte[])">
|
||||
<summary>
|
||||
Converts an array of bytes formatted as time to an array of doubles
|
||||
</summary>
|
||||
<param name="bytes"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="T:S7.Net.Types.Word">
|
||||
<summary>
|
||||
Contains the conversion methods to convert Words from S7 plc to C#.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:S7.Net.Types.Word.FromByteArray(System.Byte[])">
|
||||
<summary>
|
||||
Converts a word (2 bytes) to ushort (UInt16)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:S7.Net.Types.Word.FromBytes(System.Byte,System.Byte)">
|
||||
<summary>
|
||||
Converts a word (2 bytes) to ushort (UInt16)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:S7.Net.Types.Word.ToByteArray(System.UInt16)">
|
||||
<summary>
|
||||
Converts a ushort (UInt16) to word (2 bytes)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:S7.Net.Types.Word.ToByteArray(System.UInt16[])">
|
||||
<summary>
|
||||
Converts an array of ushort (UInt16) to an array of bytes
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:S7.Net.Types.Word.ToArray(System.Byte[])">
|
||||
<summary>
|
||||
Converts an array of bytes to an array of ushort
|
||||
</summary>
|
||||
</member>
|
||||
</members>
|
||||
</doc>
|
||||
Reference in New Issue
Block a user