mirror of
https://github.com/S7NetPlus/s7netplus.git
synced 2026-02-25 00:38:27 +08:00
Compare commits
33 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
013ff5fd92 | ||
|
|
642cf8169e | ||
|
|
f6e370b162 | ||
|
|
cbaa8921df | ||
|
|
b3458a8304 | ||
|
|
a824344a4c | ||
|
|
587e496497 | ||
|
|
0d1bc472c8 | ||
|
|
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 |
21
S7.Net.Core/S7.Net.Core.nuget.props
Normal file
21
S7.Net.Core/S7.Net.Core.nuget.props
Normal file
@@ -0,0 +1,21 @@
|
||||
<?xml version="1.0" encoding="utf-8" standalone="no"?>
|
||||
<Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup Condition=" '$(ExcludeRestorePackageImports)' != 'true' ">
|
||||
<RestoreSuccess Condition=" '$(RestoreSuccess)' == '' ">True</RestoreSuccess>
|
||||
<RestoreTool Condition=" '$(RestoreTool)' == '' ">NuGet</RestoreTool>
|
||||
<ProjectAssetsFile Condition=" '$(ProjectAssetsFile)' == '' ">C:\Users\shade\Documents\GitHub\s7netplus\S7.Net.Core\project.lock.json</ProjectAssetsFile>
|
||||
<NuGetPackageRoot Condition=" '$(NuGetPackageRoot)' == '' ">$(UserProfile)\.nuget\packages\</NuGetPackageRoot>
|
||||
<NuGetPackageFolders Condition=" '$(NuGetPackageFolders)' == '' ">C:\Users\shade\.nuget\packages\</NuGetPackageFolders>
|
||||
<NuGetProjectStyle Condition=" '$(NuGetProjectStyle)' == '' ">ProjectJson</NuGetProjectStyle>
|
||||
<NuGetToolVersion Condition=" '$(NuGetToolVersion)' == '' ">4.3.1</NuGetToolVersion>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<MSBuildAllProjects>$(MSBuildAllProjects);$(MSBuildThisFileFullPath)</MSBuildAllProjects>
|
||||
</PropertyGroup>
|
||||
<ImportGroup Condition=" '$(ExcludeRestorePackageImports)' != 'true' ">
|
||||
<Import Project="$(NuGetPackageRoot)microsoft.net.native.sharedlibrary-x86\1.7.0\build\Microsoft.Net.Native.SharedLibrary-x86.props" Condition="Exists('$(NuGetPackageRoot)microsoft.net.native.sharedlibrary-x86\1.7.0\build\Microsoft.Net.Native.SharedLibrary-x86.props')" />
|
||||
<Import Project="$(NuGetPackageRoot)microsoft.net.native.sharedlibrary-x64\1.7.0\build\Microsoft.Net.Native.SharedLibrary-x64.props" Condition="Exists('$(NuGetPackageRoot)microsoft.net.native.sharedlibrary-x64\1.7.0\build\Microsoft.Net.Native.SharedLibrary-x64.props')" />
|
||||
<Import Project="$(NuGetPackageRoot)microsoft.net.native.sharedlibrary-arm\1.7.0\build\Microsoft.Net.Native.SharedLibrary-arm.props" Condition="Exists('$(NuGetPackageRoot)microsoft.net.native.sharedlibrary-arm\1.7.0\build\Microsoft.Net.Native.SharedLibrary-arm.props')" />
|
||||
<Import Project="$(NuGetPackageRoot)microsoft.net.native.compiler\1.7.0\build\Microsoft.Net.Native.Compiler.props" Condition="Exists('$(NuGetPackageRoot)microsoft.net.native.compiler\1.7.0\build\Microsoft.Net.Native.Compiler.props')" />
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
12
S7.Net.Core/S7.Net.Core.nuget.targets
Normal file
12
S7.Net.Core/S7.Net.Core.nuget.targets
Normal file
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="utf-8" standalone="no"?>
|
||||
<Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<MSBuildAllProjects>$(MSBuildAllProjects);$(MSBuildThisFileFullPath)</MSBuildAllProjects>
|
||||
</PropertyGroup>
|
||||
<ImportGroup Condition=" '$(ExcludeRestorePackageImports)' != 'true' ">
|
||||
<Import Project="$(NuGetPackageRoot)microsoft.net.native.sharedlibrary-x86\1.7.0\build\Microsoft.Net.Native.SharedLibrary-x86.targets" Condition="Exists('$(NuGetPackageRoot)microsoft.net.native.sharedlibrary-x86\1.7.0\build\Microsoft.Net.Native.SharedLibrary-x86.targets')" />
|
||||
<Import Project="$(NuGetPackageRoot)microsoft.net.native.sharedlibrary-x64\1.7.0\build\Microsoft.Net.Native.SharedLibrary-x64.targets" Condition="Exists('$(NuGetPackageRoot)microsoft.net.native.sharedlibrary-x64\1.7.0\build\Microsoft.Net.Native.SharedLibrary-x64.targets')" />
|
||||
<Import Project="$(NuGetPackageRoot)microsoft.net.native.sharedlibrary-arm\1.7.0\build\Microsoft.Net.Native.SharedLibrary-arm.targets" Condition="Exists('$(NuGetPackageRoot)microsoft.net.native.sharedlibrary-arm\1.7.0\build\Microsoft.Net.Native.SharedLibrary-arm.targets')" />
|
||||
<Import Project="$(NuGetPackageRoot)microsoft.net.native.compiler\1.7.0\build\Microsoft.Net.Native.Compiler.targets" Condition="Exists('$(NuGetPackageRoot)microsoft.net.native.compiler\1.7.0\build\Microsoft.Net.Native.Compiler.targets')" />
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
@@ -1,9 +1,9 @@
|
||||
{
|
||||
"dependencies": {
|
||||
"Microsoft.NETCore.UniversalWindowsPlatform": "5.0.0"
|
||||
"Microsoft.NETCore.UniversalWindowsPlatform": "5.4.0"
|
||||
},
|
||||
"frameworks": {
|
||||
"uap10.0": {}
|
||||
"uap10.0.10240": {}
|
||||
},
|
||||
"runtimes": {
|
||||
"win10-arm": {},
|
||||
|
||||
@@ -6,7 +6,7 @@ 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
|
||||
|
||||
|
||||
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; }
|
||||
}
|
||||
}
|
||||
@@ -60,6 +60,7 @@
|
||||
<Compile Include="Helpers\TestClassWithCustomType.cs" />
|
||||
<Compile Include="Helpers\TestClassWithPrivateSetters.cs" />
|
||||
<Compile Include="Helpers\TestLongClass.cs" />
|
||||
<Compile Include="Helpers\TestSmallClass.cs" />
|
||||
<Compile Include="Snap7\snap7.net.cs" />
|
||||
<Compile Include="Helpers\TestClass.cs" />
|
||||
<Compile Include="Helpers\TestStruct.cs" />
|
||||
|
||||
@@ -386,19 +386,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 +439,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 +529,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]
|
||||
@@ -664,8 +750,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.");
|
||||
@@ -757,6 +843,55 @@ namespace S7.Net.UnitTest
|
||||
Assert.IsTrue(reachablePlc.IsAvailable);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void T26_ReadWriteDouble()
|
||||
{
|
||||
double test_value = 55.66;
|
||||
plc.Write("DB1.DBD0", test_value);
|
||||
Assert.AreEqual(plc.LastErrorCode, ErrorCode.NoError, "Write Double");
|
||||
var helper = plc.Read("DB1.DBD0");
|
||||
double test_value2 = Conversion.ConvertToDouble((uint)helper);
|
||||
|
||||
Assert.AreEqual(plc.LastErrorCode, ErrorCode.NoError, "Read Double");
|
||||
Assert.AreEqual(test_value, test_value2, 0.01, "Compare Write/Read"); //Need delta here because S7 only has 32 bit reals
|
||||
}
|
||||
|
||||
[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]);
|
||||
}
|
||||
}
|
||||
|
||||
[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();
|
||||
tc.Bool1 = true;
|
||||
|
||||
plc.WriteClass(tc, DB2);
|
||||
var tc2 = plc.ReadClass<TestSmallClass>(DB2);
|
||||
|
||||
Assert.AreEqual(tc.Bool1, tc2.Bool1);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private methods
|
||||
|
||||
97
S7.Net/COTP.cs
Normal file
97
S7.Net/COTP.cs
Normal file
@@ -0,0 +1,97 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Net.Sockets;
|
||||
|
||||
namespace S7.Net
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// COTP Protocol functions and types
|
||||
/// </summary>
|
||||
internal class COTP
|
||||
{
|
||||
/// <summary>
|
||||
/// Describes a COTP TPDU (Transport protocol data unit)
|
||||
/// </summary>
|
||||
public class TPDU
|
||||
{
|
||||
public byte HeaderLength;
|
||||
public byte PDUType;
|
||||
public int TPDUNumber;
|
||||
public byte[] Data;
|
||||
public bool LastDataUnit;
|
||||
|
||||
public TPDU(TPKT tPKT)
|
||||
{
|
||||
var br = new BinaryReader(new MemoryStream(tPKT.Data));
|
||||
HeaderLength = br.ReadByte();
|
||||
if (HeaderLength >= 2)
|
||||
{
|
||||
PDUType = br.ReadByte();
|
||||
if (PDUType == 0xf0) //DT Data
|
||||
{
|
||||
var flags = br.ReadByte();
|
||||
TPDUNumber = flags & 0x7F;
|
||||
LastDataUnit = (flags & 0x80) > 0;
|
||||
Data = br.ReadBytes(tPKT.Length - HeaderLength - 4); //4 = TPKT Size
|
||||
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="socket">The socket to read from</param>
|
||||
/// <returns>COTP DPDU instance</returns>
|
||||
public static TPDU Read(Socket socket)
|
||||
{
|
||||
var tpkt = TPKT.Read(socket);
|
||||
if (tpkt.Length > 0) return new TPDU(tpkt);
|
||||
return null;
|
||||
}
|
||||
|
||||
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>
|
||||
/// <returns>Data in TSDU</returns>
|
||||
public static byte[] Read(Socket socket)
|
||||
{
|
||||
var segment = TPDU.Read(socket);
|
||||
if (segment == null) return null;
|
||||
|
||||
var output = new MemoryStream(segment.Data.Length);
|
||||
output.Write(segment.Data, 0, segment.Data.Length);
|
||||
|
||||
while (!segment.LastDataUnit)
|
||||
{
|
||||
segment = TPDU.Read(socket);
|
||||
output.Write(segment.Data, (int)output.Position, segment.Data.Length);
|
||||
}
|
||||
return output.GetBuffer();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -163,6 +163,11 @@
|
||||
/// </summary>
|
||||
String,
|
||||
|
||||
/// <summary>
|
||||
/// String variable type (variable)
|
||||
/// </summary>
|
||||
StringEx,
|
||||
|
||||
/// <summary>
|
||||
/// Timer variable type
|
||||
/// </summary>
|
||||
|
||||
304
S7.Net/PLC.cs
304
S7.Net/PLC.cs
@@ -1,13 +1,11 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.NetworkInformation;
|
||||
using System.Net.Sockets;
|
||||
using S7.Net.Types;
|
||||
using Double = System.Double;
|
||||
|
||||
|
||||
namespace S7.Net
|
||||
{
|
||||
@@ -17,31 +15,37 @@ namespace S7.Net
|
||||
public class Plc : IDisposable
|
||||
{
|
||||
private const int CONNECTION_TIMED_OUT_ERROR_CODE = 10060;
|
||||
|
||||
private Socket _mSocket; //TCP connection to device
|
||||
|
||||
//TCP connection to device
|
||||
private Socket _mSocket;
|
||||
|
||||
/// <summary>
|
||||
/// Ip address of the plc
|
||||
/// IP address of the PLC
|
||||
/// </summary>
|
||||
public string IP { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Cpu type of the plc
|
||||
/// CPU type of the PLC
|
||||
/// </summary>
|
||||
public CpuType CPU { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Rack of the plc
|
||||
/// Rack of the PLC
|
||||
/// </summary>
|
||||
public Int16 Rack { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Slot of the CPU of the plc
|
||||
/// Slot of the CPU of the PLC
|
||||
/// </summary>
|
||||
public Int16 Slot { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Max PDU size this cpu supports
|
||||
/// </summary>
|
||||
public Int16 MaxPDUSize { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if a connection to the plc can be established
|
||||
/// Returns true if a connection to the PLC can be established
|
||||
/// </summary>
|
||||
public bool IsAvailable
|
||||
{
|
||||
@@ -61,7 +65,7 @@ namespace S7.Net
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the socket is connected and polls the other peer (the plc) to see if it's connected.
|
||||
/// 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>
|
||||
@@ -100,17 +104,24 @@ namespace S7.Net
|
||||
/// 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.
|
||||
/// <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>
|
||||
public Plc(CpuType cpu, string ip, Int16 rack, Int16 slot)
|
||||
{
|
||||
IP = ip;
|
||||
if (!Enum.IsDefined(typeof(CpuType), cpu))
|
||||
throw new InvalidEnumArgumentException(nameof(cpu), (int) cpu, typeof(CpuType));
|
||||
|
||||
if (string.IsNullOrEmpty(ip))
|
||||
throw new ArgumentException("IP address must valid.", nameof(ip));
|
||||
|
||||
CPU = cpu;
|
||||
IP = ip;
|
||||
Rack = rack;
|
||||
Slot = slot;
|
||||
MaxPDUSize = 240;
|
||||
}
|
||||
|
||||
private ErrorCode Connect(Socket socket)
|
||||
@@ -125,7 +136,7 @@ namespace S7.Net
|
||||
catch (SocketException sex)
|
||||
{
|
||||
// see https://msdn.microsoft.com/en-us/library/windows/desktop/ms740668(v=vs.85).aspx
|
||||
if (sex.ErrorCode == CONNECTION_TIMED_OUT_ERROR_CODE)
|
||||
if (sex.SocketErrorCode == SocketError.TimedOut)
|
||||
{
|
||||
LastErrorCode = ErrorCode.IPAddressNotAvailable;
|
||||
}
|
||||
@@ -146,12 +157,12 @@ namespace S7.Net
|
||||
}
|
||||
|
||||
/// <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.
|
||||
/// Open a <see cref="Socket"/> and connects to the PLC, sending all the corrected package
|
||||
/// and returning if the connection was successful (<see cref="ErrorCode.NoError"/>) of it was wrong.
|
||||
/// </summary>
|
||||
/// <returns>Returns ErrorCode.NoError if the connection was successful, otherwise check the ErrorCode</returns>
|
||||
public ErrorCode Open()
|
||||
{
|
||||
byte[] bReceive = new byte[256];
|
||||
|
||||
_mSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
|
||||
_mSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout, 1000);
|
||||
@@ -162,9 +173,25 @@ namespace S7.Net
|
||||
return LastErrorCode;
|
||||
}
|
||||
|
||||
try
|
||||
try
|
||||
{
|
||||
byte[] bSend1 = { 3, 0, 0, 22, 17, 224, 0, 0, 0, 46, 0, 193, 2, 1, 0, 194, 2, 3, 0, 192, 1, 9 };
|
||||
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
|
||||
9 //TPDU Size (2^9 = 512)
|
||||
};
|
||||
|
||||
switch (CPU) {
|
||||
case CpuType.S7200:
|
||||
@@ -220,32 +247,33 @@ namespace S7.Net
|
||||
return ErrorCode.WrongCPU_Type;
|
||||
}
|
||||
|
||||
//COTP Setup
|
||||
_mSocket.Send(bSend1, 22, SocketFlags.None);
|
||||
if (_mSocket.Receive(bReceive, 22, SocketFlags.None) != 22)
|
||||
{
|
||||
throw new Exception(ErrorCode.WrongNumberReceivedBytes.ToString());
|
||||
}
|
||||
byte[] bsend2 = { 3, 0, 0, 25, 2, 240, 128, 50, 1, 0, 0, 255, 255, 0, 8, 0, 0, 240, 0, 0, 3, 0, 3,
|
||||
7, 80 //Try 1920 PDU Size. Same as libnodave.
|
||||
};
|
||||
|
||||
byte[] bsend2 = { 3, 0, 0, 25, 2, 240, 128, 50, 1, 0, 0, 255, 255, 0, 8, 0, 0, 240, 0, 0, 3, 0, 3, 1, 0 };
|
||||
_mSocket.Send(bsend2, 25, SocketFlags.None);
|
||||
|
||||
if (_mSocket.Receive(bReceive, 27, SocketFlags.None) != 27)
|
||||
var s7data = COTP.TSDU.Read(_mSocket);
|
||||
if (s7data == null || s7data[1] != 0x03) //Check for S7 Ack Data
|
||||
{
|
||||
throw new Exception(ErrorCode.WrongNumberReceivedBytes.ToString());
|
||||
}
|
||||
}
|
||||
MaxPDUSize = (short)(s7data[18] * 256 + s7data[19]);
|
||||
|
||||
return ErrorCode.NoError;
|
||||
}
|
||||
catch(Exception exc)
|
||||
catch (Exception exc)
|
||||
{
|
||||
LastErrorCode = ErrorCode.ConnectionError;
|
||||
LastErrorString = "Couldn't establish the connection to " + IP + ".\nMessage: " + exc.Message;
|
||||
LastErrorString = string.Format("Couldn't establish the connection to {0}.\nMessage: {1}", IP, exc.Message);
|
||||
return ErrorCode.ConnectionError;
|
||||
}
|
||||
|
||||
return ErrorCode.NoError;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Disonnects from the plc and close the socket
|
||||
/// Disonnects from the PLC and close the socket
|
||||
/// </summary>
|
||||
public void Close()
|
||||
{
|
||||
@@ -267,10 +295,14 @@ namespace S7.Net
|
||||
public void ReadMultipleVars(List<DataItem> dataItems)
|
||||
{
|
||||
int cntBytes = dataItems.Sum(dataItem => VarTypeToByteLength(dataItem.VarType, dataItem.Count));
|
||||
|
||||
if (dataItems.Count > 20) throw new Exception("Too many vars requested");
|
||||
if (cntBytes > 222) throw new Exception("Too many bytes requested"); //todo, proper TDU check + split in multiple requests
|
||||
|
||||
//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.
|
||||
if (dataItems.Count > 20)
|
||||
throw new Exception("Too many vars requested");
|
||||
if (cntBytes > 222)
|
||||
throw new Exception("Too many bytes requested"); // TODO: proper TDU check + split in multiple requests
|
||||
try
|
||||
{
|
||||
// first create the header
|
||||
@@ -285,24 +317,34 @@ namespace S7.Net
|
||||
|
||||
_mSocket.Send(package.array, package.array.Length, SocketFlags.None);
|
||||
|
||||
byte[] bReceive = new byte[512];
|
||||
int numReceived = _mSocket.Receive(bReceive, 512, SocketFlags.None);
|
||||
if (bReceive[21] != 0xff) throw new Exception(ErrorCode.WrongNumberReceivedBytes.ToString());
|
||||
var s7data = COTP.TSDU.Read(_mSocket);
|
||||
if (s7data == null || s7data[14] != 0xff)
|
||||
throw new Exception(ErrorCode.WrongNumberReceivedBytes.ToString());
|
||||
|
||||
int offset = 25;
|
||||
int offset = 14;
|
||||
foreach (var dataItem in dataItems)
|
||||
{
|
||||
// check for Return Code = Success
|
||||
if (s7data[offset] != 0xff)
|
||||
throw new Exception(ErrorCode.WrongNumberReceivedBytes.ToString());
|
||||
|
||||
// to Data bytes
|
||||
offset += 4;
|
||||
|
||||
int byteCnt = VarTypeToByteLength(dataItem.VarType, dataItem.Count);
|
||||
byte[] bytes = new byte[byteCnt];
|
||||
dataItem.Value = ParseBytes(
|
||||
dataItem.VarType,
|
||||
s7data.Skip(offset).Take(byteCnt).ToArray(),
|
||||
dataItem.Count,
|
||||
dataItem.BitAdr
|
||||
);
|
||||
|
||||
for (int i = 0; i < byteCnt; i++)
|
||||
{
|
||||
bytes[i] = bReceive[i + offset];
|
||||
}
|
||||
// next Item
|
||||
offset += byteCnt;
|
||||
|
||||
offset += byteCnt + 4;
|
||||
|
||||
dataItem.Value = ParseBytes(dataItem.VarType, bytes, dataItem.Count);
|
||||
// Fill byte in response when bytecount is odd
|
||||
if (dataItem.Count % 2 != 0 && (dataItem.VarType == VarType.Byte || dataItem.VarType == VarType.Bit))
|
||||
offset++;
|
||||
}
|
||||
}
|
||||
catch (SocketException socketException)
|
||||
@@ -332,7 +374,8 @@ namespace S7.Net
|
||||
int index = startByteAdr;
|
||||
while (count > 0)
|
||||
{
|
||||
var maxToRead = (int)Math.Min(count, 200);
|
||||
//This works up to MaxPDUSize-1 on SNAP7. But not MaxPDUSize-0.
|
||||
var maxToRead = (int)Math.Min(count, MaxPDUSize-18);
|
||||
byte[] bytes = ReadBytesWithASingleRequest(dataType, db, index, maxToRead);
|
||||
if (bytes == null)
|
||||
return resultBytes.ToArray();
|
||||
@@ -343,6 +386,8 @@ namespace S7.Net
|
||||
return resultBytes.ToArray();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <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).
|
||||
@@ -352,17 +397,18 @@ namespace S7.Net
|
||||
/// <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)
|
||||
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);
|
||||
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.
|
||||
/// 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>
|
||||
@@ -484,7 +530,8 @@ namespace S7.Net
|
||||
}
|
||||
|
||||
string txt2 = txt.Substring(1);
|
||||
if (txt2.IndexOf(".") == -1) throw new Exception();
|
||||
if (txt2.IndexOf(".") == -1)
|
||||
throw new Exception();
|
||||
|
||||
mByte = int.Parse(txt2.Substring(0, txt2.IndexOf(".")));
|
||||
mBit = int.Parse(txt2.Substring(txt2.IndexOf(".") + 1));
|
||||
@@ -532,7 +579,7 @@ namespace S7.Net
|
||||
}
|
||||
|
||||
/// <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.
|
||||
/// 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>
|
||||
@@ -556,28 +603,28 @@ namespace S7.Net
|
||||
}
|
||||
|
||||
/// <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.
|
||||
/// 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>
|
||||
/// <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.
|
||||
/// 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>
|
||||
/// <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();
|
||||
@@ -605,7 +652,10 @@ namespace S7.Net
|
||||
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 = (int)Math.Min(count, 200);
|
||||
ErrorCode lastError = WriteBytesWithASingleRequest(dataType, db, startByteAdr + localIndex, value.Skip(localIndex).Take(maxToWrite).ToArray());
|
||||
if (lastError != ErrorCode.NoError)
|
||||
@@ -685,7 +735,7 @@ namespace S7.Net
|
||||
{
|
||||
var intValue = (int) value;
|
||||
if (intValue < 0 || intValue > 7)
|
||||
throw new Exception(string.Format("Addressing Error: You can only reference bitwise locations 0-7. Address {0} is invalid", bitAdr));
|
||||
throw new ArgumentOutOfRangeException(string.Format("Addressing Error: You can only reference bitwise locations 0-7. Address {0} is invalid", bitAdr), nameof(bitAdr));
|
||||
|
||||
bitValue = intValue == 1;
|
||||
}
|
||||
@@ -715,7 +765,7 @@ namespace S7.Net
|
||||
package = Types.DWord.ToByteArray((UInt32)value);
|
||||
break;
|
||||
case "Double":
|
||||
package = Types.Double.ToByteArray((Double)value);
|
||||
package = Types.Double.ToByteArray((double)value);
|
||||
break;
|
||||
case "Byte[]":
|
||||
package = (byte[])value;
|
||||
@@ -746,11 +796,11 @@ namespace S7.Net
|
||||
}
|
||||
|
||||
/// <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.
|
||||
/// 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="value">Value to be written to the PLC</param>
|
||||
/// <returns>NoError if it was successful, or the error is specified</returns>
|
||||
public ErrorCode Write(string variable, object value)
|
||||
{
|
||||
@@ -799,10 +849,11 @@ namespace S7.Net
|
||||
{
|
||||
return Write(DataType.DataBlock, mDB, dbIndex, (Int32)value);
|
||||
}
|
||||
else
|
||||
else if (value is double)
|
||||
{
|
||||
objValue = Convert.ChangeType(value, typeof(UInt32));
|
||||
return Write(DataType.DataBlock, mDB, dbIndex, value);
|
||||
}
|
||||
objValue = Convert.ChangeType(value, typeof(UInt32));
|
||||
return Write(DataType.DataBlock, mDB, dbIndex, (UInt32)objValue);
|
||||
case "DBX":
|
||||
mByte = dbIndex;
|
||||
@@ -908,17 +959,17 @@ namespace S7.Net
|
||||
catch(Exception exc)
|
||||
{
|
||||
LastErrorCode = ErrorCode.WrongVarFormat;
|
||||
LastErrorString = "The variable'" + variable + "' could not be parsed. Please check the syntax and try again.\nException: " + exc.Message;
|
||||
LastErrorString = string.Format("The variable'{0}' could not be parsed. Please check the syntax and try again.\nException: {1}", variable, exc.Message);
|
||||
return LastErrorCode;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a C# struct to a DB in the plc
|
||||
/// 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="startByteAdr">Start bytes on the PLC</param>
|
||||
/// <returns>NoError if it was successful, or the error is specified</returns>
|
||||
public ErrorCode WriteStruct(object structValue, int db, int startByteAdr = 0)
|
||||
{
|
||||
@@ -928,11 +979,11 @@ namespace S7.Net
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a C# class to a DB in the plc
|
||||
/// 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="startByteAdr">Start bytes on the PLC</param>
|
||||
/// <returns>NoError if it was successful, or the error is specified</returns>
|
||||
public ErrorCode WriteClass(object classValue, int db, int startByteAdr = 0)
|
||||
{
|
||||
@@ -942,7 +993,7 @@ namespace S7.Net
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the LastErrorCode to NoError and LastErrorString to String.Empty
|
||||
/// Sets the <see cref="LastErrorCode"/> to <see cref="ErrorCode.NoError"/> and <see cref="LastErrorString"/> to <see cref="string.Empty"/>.
|
||||
/// </summary>
|
||||
public void ClearLastError()
|
||||
{
|
||||
@@ -951,7 +1002,7 @@ namespace S7.Net
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates the header to read bytes from the plc
|
||||
/// Creates the header to read bytes from the PLC
|
||||
/// </summary>
|
||||
/// <param name="amount"></param>
|
||||
/// <returns></returns>
|
||||
@@ -973,7 +1024,7 @@ namespace S7.Net
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create the bytes-package to request data from the plc. You have to specify the memory type (dataType),
|
||||
/// 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>
|
||||
@@ -1018,8 +1069,6 @@ namespace S7.Net
|
||||
|
||||
private byte[] ReadBytesWithASingleRequest(DataType dataType, int db, int startByteAdr, int count)
|
||||
{
|
||||
byte[] bytes = new byte[count];
|
||||
|
||||
try
|
||||
{
|
||||
// first create the header
|
||||
@@ -1031,15 +1080,11 @@ namespace S7.Net
|
||||
|
||||
_mSocket.Send(package.array, package.array.Length, SocketFlags.None);
|
||||
|
||||
byte[] bReceive = new byte[512];
|
||||
int numReceived = _mSocket.Receive(bReceive, 512, SocketFlags.None);
|
||||
if (bReceive[21] != 0xff)
|
||||
var s7data = COTP.TSDU.Read(_mSocket);
|
||||
if (s7data == null || s7data[14] != 0xff)
|
||||
throw new Exception(ErrorCode.WrongNumberReceivedBytes.ToString());
|
||||
|
||||
for (int cnt = 0; cnt < count; cnt++)
|
||||
bytes[cnt] = bReceive[cnt + 25];
|
||||
|
||||
return bytes;
|
||||
return s7data.Skip(18).Take(count).ToArray();
|
||||
}
|
||||
catch (SocketException socketException)
|
||||
{
|
||||
@@ -1056,7 +1101,7 @@ namespace S7.Net
|
||||
}
|
||||
|
||||
/// <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.
|
||||
/// 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>
|
||||
@@ -1066,9 +1111,7 @@ namespace S7.Net
|
||||
/// <returns>NoError if it was successful, or the error is specified</returns>
|
||||
private ErrorCode WriteBytesWithASingleRequest(DataType dataType, int db, int startByteAdr, byte[] value)
|
||||
{
|
||||
byte[] bReceive = new byte[513];
|
||||
int varCount = 0;
|
||||
|
||||
try
|
||||
{
|
||||
varCount = value.Length;
|
||||
@@ -1097,8 +1140,8 @@ namespace S7.Net
|
||||
|
||||
_mSocket.Send(package.array, package.array.Length, SocketFlags.None);
|
||||
|
||||
int numReceived = _mSocket.Receive(bReceive, 512, SocketFlags.None);
|
||||
if (bReceive[21] != 0xff)
|
||||
var s7data = COTP.TSDU.Read(_mSocket);
|
||||
if (s7data == null || s7data[14] != 0xff)
|
||||
{
|
||||
throw new Exception(ErrorCode.WrongNumberReceivedBytes.ToString());
|
||||
}
|
||||
@@ -1115,7 +1158,6 @@ namespace S7.Net
|
||||
|
||||
private ErrorCode WriteBitWithASingleRequest(DataType dataType, int db, int startByteAdr, int bitAdr, bool bitValue)
|
||||
{
|
||||
byte[] bReceive = new byte[513];
|
||||
int varCount = 0;
|
||||
|
||||
try
|
||||
@@ -1136,7 +1178,7 @@ namespace S7.Net
|
||||
package.Add(Types.Word.ToByteArray((ushort)varCount));
|
||||
package.Add(Types.Word.ToByteArray((ushort)(db)));
|
||||
package.Add((byte)dataType);
|
||||
var overflow = (int)(startByteAdr * 8 + bitAdr / 0xffffU); // handles words with address bigger than 8191
|
||||
int overflow = (int)(startByteAdr * 8 / 0xffffU); // handles words with address bigger than 8191
|
||||
package.Add((byte)overflow);
|
||||
package.Add(Types.Word.ToByteArray((ushort)(startByteAdr * 8 + bitAdr)));
|
||||
package.Add(new byte[] { 0, 0x03 }); //ending 0x03 is used for writing a sinlge bit
|
||||
@@ -1147,11 +1189,9 @@ namespace S7.Net
|
||||
|
||||
_mSocket.Send(package.array, package.array.Length, SocketFlags.None);
|
||||
|
||||
int numReceived = _mSocket.Receive(bReceive, 512, SocketFlags.None);
|
||||
if (bReceive[21] != 0xff)
|
||||
{
|
||||
throw new Exception(ErrorCode.WrongNumberReceivedBytes.ToString());
|
||||
}
|
||||
var s7data = COTP.TSDU.Read(_mSocket);
|
||||
if (s7data == null || s7data[14] != 0xff)
|
||||
throw new Exception(ErrorCode.WrongNumberReceivedBytes.ToString());
|
||||
|
||||
return ErrorCode.NoError;
|
||||
}
|
||||
@@ -1169,10 +1209,12 @@ namespace S7.Net
|
||||
/// <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)
|
||||
private object ParseBytes(VarType varType, byte[] bytes, int varCount, byte bitAdr = 0)
|
||||
{
|
||||
if (bytes == null) return null;
|
||||
if (bytes == null)
|
||||
return null;
|
||||
|
||||
switch (varType)
|
||||
{
|
||||
@@ -1206,8 +1248,12 @@ namespace S7.Net
|
||||
return Types.Double.FromByteArray(bytes);
|
||||
else
|
||||
return Types.Double.ToArray(bytes);
|
||||
|
||||
case VarType.String:
|
||||
return Types.String.FromByteArray(bytes);
|
||||
case VarType.StringEx:
|
||||
return Types.StringEx.FromByteArray(bytes);
|
||||
|
||||
case VarType.Timer:
|
||||
if (varCount == 1)
|
||||
return Types.Timer.FromByteArray(bytes);
|
||||
@@ -1219,18 +1265,28 @@ namespace S7.Net
|
||||
else
|
||||
return Types.Counter.ToArray(bytes);
|
||||
case VarType.Bit:
|
||||
return null; //TODO
|
||||
if (varCount == 1)
|
||||
{
|
||||
if (bitAdr > 7)
|
||||
return null;
|
||||
else
|
||||
return Types.Bit.FromByte(bytes[0], bitAdr);
|
||||
}
|
||||
else
|
||||
{
|
||||
return Types.Bit.ToBitArray(bytes);
|
||||
}
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Given a S7 variable type (Bool, Word, DWord, etc.), it returns how many bytes to read.
|
||||
/// 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></returns>
|
||||
/// <returns>Byte lenght of variable</returns>
|
||||
private int VarTypeToByteLength(VarType varType, int varCount = 1)
|
||||
{
|
||||
switch (varType)
|
||||
@@ -1241,6 +1297,8 @@ namespace S7.Net
|
||||
return (varCount < 1) ? 1 : varCount;
|
||||
case VarType.String:
|
||||
return varCount;
|
||||
case VarType.StringEx:
|
||||
return varCount + 2;
|
||||
case VarType.Word:
|
||||
case VarType.Timer:
|
||||
case VarType.Int:
|
||||
@@ -1255,23 +1313,53 @@ namespace S7.Net
|
||||
}
|
||||
}
|
||||
|
||||
#region IDisposable members
|
||||
#region IDisposable Support
|
||||
private bool disposedValue = false; // To detect redundant calls
|
||||
|
||||
/// <summary>
|
||||
/// Releases all resources, disonnects from the plc and closes the socket
|
||||
/// Releases all resources, disonnects from the PLC and closes the <see cref="Socket"/>
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (_mSocket != null)
|
||||
if (!disposedValue)
|
||||
{
|
||||
if (_mSocket.Connected)
|
||||
if (disposing)
|
||||
{
|
||||
_mSocket.Shutdown(SocketShutdown.Both);
|
||||
_mSocket.Close();
|
||||
// TODO: dispose managed state (managed objects).
|
||||
if (_mSocket != null)
|
||||
{
|
||||
if (_mSocket.Connected)
|
||||
{
|
||||
_mSocket.Shutdown(SocketShutdown.Both);
|
||||
_mSocket.Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: free unmanaged resources (unmanaged objects) and override a finalizer below.
|
||||
// TODO: set large fields to null.
|
||||
|
||||
disposedValue = true;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: override a finalizer only if Dispose(bool disposing) above has code to free unmanaged resources.
|
||||
// ~Plc() {
|
||||
// // Do not change this code. Put cleanup code in Dispose(bool disposing) above.
|
||||
// Dispose(false);
|
||||
// }
|
||||
|
||||
// This code added to correctly implement the disposable pattern.
|
||||
/// <summary>
|
||||
/// Releases all resources, disonnects from the PLC and closes the <see cref="Socket"/>
|
||||
/// </summary>
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -77,9 +77,12 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Conversion.cs" />
|
||||
<Compile Include="COTP.cs" />
|
||||
<Compile Include="Enums.cs" />
|
||||
<Compile Include="PLC.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="TPKT.cs" />
|
||||
<Compile Include="Types\Bit.cs" />
|
||||
<Compile Include="Types\Boolean.cs" />
|
||||
<Compile Include="Types\Byte.cs" />
|
||||
<Compile Include="Types\ByteArray.cs" />
|
||||
@@ -90,6 +93,7 @@
|
||||
<Compile Include="Types\Double.cs" />
|
||||
<Compile Include="Types\DWord.cs" />
|
||||
<Compile Include="Types\Int.cs" />
|
||||
<Compile Include="Types\StringEx.cs" />
|
||||
<Compile Include="Types\String.cs" />
|
||||
<Compile Include="Types\Struct.cs" />
|
||||
<Compile Include="Types\Timer.cs" />
|
||||
|
||||
49
S7.Net/TPKT.cs
Normal file
49
S7.Net/TPKT.cs
Normal file
@@ -0,0 +1,49 @@
|
||||
using System;
|
||||
using System.Net.Sockets;
|
||||
|
||||
namespace S7.Net
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Describes a TPKT Packet
|
||||
/// </summary>
|
||||
internal class TPKT
|
||||
{
|
||||
public byte Version;
|
||||
public byte Reserved1;
|
||||
public int Length;
|
||||
public byte[] Data;
|
||||
|
||||
/// <summary>
|
||||
/// Reds a TPKT from the socket
|
||||
/// </summary>
|
||||
/// <param name="socket">The socket to read from</param>
|
||||
/// <returns>TPKT Instace</returns>
|
||||
public static TPKT Read(Socket socket)
|
||||
{
|
||||
var buf = new byte[4];
|
||||
socket.Receive(buf, 4, SocketFlags.None);
|
||||
var pkt = new TPKT
|
||||
{
|
||||
Version = buf[0],
|
||||
Reserved1 = buf[1],
|
||||
Length = buf[2] * 256 + buf[3] //BigEndian
|
||||
};
|
||||
if (pkt.Length > 0)
|
||||
{
|
||||
pkt.Data = new byte[pkt.Length - 4];
|
||||
socket.Receive(pkt.Data, pkt.Length - 4, SocketFlags.None);
|
||||
}
|
||||
return pkt;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return string.Format("Version: {0} Length: {1} Data: {2}",
|
||||
Version,
|
||||
Length,
|
||||
BitConverter.ToString(Data)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
28
S7.Net/Types/Bit.cs
Normal file
28
S7.Net/Types/Bit.cs
Normal file
@@ -0,0 +1,28 @@
|
||||
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>
|
||||
public static BitArray ToBitArray(byte[] bytes)
|
||||
{
|
||||
BitArray bitArr = new BitArray(bytes);
|
||||
return bitArr;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -12,10 +12,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 +20,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 +28,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>
|
||||
|
||||
@@ -99,6 +99,10 @@ namespace S7.Net.Types
|
||||
numBytes = GetIncreasedNumberOfBytes(numBytes, property.PropertyType);
|
||||
}
|
||||
}
|
||||
// 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 (int)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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -25,6 +25,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>
|
||||
|
||||
@@ -16,38 +16,15 @@ namespace S7.Net.Types
|
||||
{
|
||||
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)
|
||||
// sps uses bigending so we have to reverse if platform needs
|
||||
if (BitConverter.IsLittleEndian)
|
||||
{
|
||||
return 0.0;
|
||||
// create deep copy of the array and reverse
|
||||
bytes = new byte[] { bytes[3], bytes[2], bytes[1], bytes[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;
|
||||
}
|
||||
return BitConverter.ToSingle(bytes, 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -76,48 +53,13 @@ namespace S7.Net.Types
|
||||
/// </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;
|
||||
byte[] bytes = BitConverter.GetBytes((float)(value));
|
||||
|
||||
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;
|
||||
// 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>
|
||||
@@ -145,38 +87,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[1] = (byte)((int)value & 0xFF);
|
||||
bytes[0] = (byte)((int)value >> 8 & 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)((int)value[i] & 0xFF);
|
||||
bytes[bytesPos++] = (byte)(((int)value[i] >> 8) & 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;
|
||||
|
||||
@@ -3,19 +3,14 @@
|
||||
/// <summary>
|
||||
/// Contains the methods to convert from S7 strings to C# strings
|
||||
/// </summary>
|
||||
public static class String
|
||||
public class String
|
||||
{
|
||||
/// <summary>
|
||||
/// Converts a string to S7 bytes
|
||||
/// </summary>
|
||||
public static byte[] ToByteArray(string value)
|
||||
{
|
||||
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());
|
||||
return bytes;
|
||||
return System.Text.Encoding.ASCII.GetBytes(value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -27,13 +22,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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
26
S7.Net/Types/StringEx.cs
Normal file
26
S7.Net/Types/StringEx.cs
Normal file
@@ -0,0 +1,26 @@
|
||||
namespace S7.Net.Types
|
||||
{
|
||||
/// <summary>
|
||||
/// Contains the methods to convert from S7 strings to C# strings
|
||||
/// there are two kinds how strings a send. This one is with a pre of two bytes
|
||||
/// they contain the length of the string
|
||||
/// </summary>
|
||||
public static class StringEx
|
||||
{
|
||||
/// <summary>
|
||||
/// Converts S7 bytes to a string
|
||||
/// </summary>
|
||||
/// <param name="bytes"></param>
|
||||
/// <returns></returns>
|
||||
public static string FromByteArray(byte[] bytes)
|
||||
{
|
||||
if (bytes.Length < 2) return "";
|
||||
|
||||
int size = bytes[0];
|
||||
int length = bytes[1];
|
||||
|
||||
return System.Text.Encoding.ASCII.GetString(bytes, 2, length);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
Binary file not shown.
@@ -343,7 +343,7 @@
|
||||
<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)">
|
||||
<member name="M:S7.Net.Plc.Read(S7.Net.DataType,System.Int32,System.Int32,S7.Net.VarType,System.Int32,System.Byte)">
|
||||
<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).
|
||||
@@ -353,6 +353,7 @@
|
||||
<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>
|
||||
</member>
|
||||
<member name="M:S7.Net.Plc.Read(System.String)">
|
||||
@@ -520,13 +521,14 @@
|
||||
<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)">
|
||||
<member name="M:S7.Net.Plc.ParseBytes(S7.Net.VarType,System.Byte[],System.Int32,System.Byte)">
|
||||
<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>
|
||||
</member>
|
||||
<member name="M:S7.Net.Plc.VarTypeToByteLength(S7.Net.VarType,System.Int32)">
|
||||
@@ -542,6 +544,21 @@
|
||||
Releases all resources, disonnects from the plc and closes the socket
|
||||
</summary>
|
||||
</member>
|
||||
<member name="T:S7.Net.Types.Bit">
|
||||
<summary>
|
||||
Contains the conversion methods to convert Bit from S7 plc to C#.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:S7.Net.Types.Bit.FromByte(System.Byte,System.Byte)">
|
||||
<summary>
|
||||
Converts a Bit to bool
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:S7.Net.Types.Bit.ToBitArray(System.Byte[])">
|
||||
<summary>
|
||||
Converts an array of bytes to a BitArray
|
||||
</summary>
|
||||
</member>
|
||||
<member name="T:S7.Net.Types.Boolean">
|
||||
<summary>
|
||||
Contains the methods to read, set and reset bits inside bytes
|
||||
|
||||
Binary file not shown.
@@ -343,7 +343,7 @@
|
||||
<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)">
|
||||
<member name="M:S7.Net.Plc.Read(S7.Net.DataType,System.Int32,System.Int32,S7.Net.VarType,System.Int32,System.Byte)">
|
||||
<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).
|
||||
@@ -353,6 +353,7 @@
|
||||
<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>
|
||||
</member>
|
||||
<member name="M:S7.Net.Plc.Read(System.String)">
|
||||
@@ -520,13 +521,14 @@
|
||||
<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)">
|
||||
<member name="M:S7.Net.Plc.ParseBytes(S7.Net.VarType,System.Byte[],System.Int32,System.Byte)">
|
||||
<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>
|
||||
</member>
|
||||
<member name="M:S7.Net.Plc.VarTypeToByteLength(S7.Net.VarType,System.Int32)">
|
||||
@@ -542,6 +544,21 @@
|
||||
Releases all resources, disonnects from the plc and closes the socket
|
||||
</summary>
|
||||
</member>
|
||||
<member name="T:S7.Net.Types.Bit">
|
||||
<summary>
|
||||
Contains the conversion methods to convert Bit from S7 plc to C#.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:S7.Net.Types.Bit.FromByte(System.Byte,System.Byte)">
|
||||
<summary>
|
||||
Converts a Bit to bool
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:S7.Net.Types.Bit.ToBitArray(System.Byte[])">
|
||||
<summary>
|
||||
Converts an array of bytes to a BitArray
|
||||
</summary>
|
||||
</member>
|
||||
<member name="T:S7.Net.Types.Boolean">
|
||||
<summary>
|
||||
Contains the methods to read, set and reset bits inside bytes
|
||||
|
||||
Binary file not shown.
@@ -343,7 +343,7 @@
|
||||
<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)">
|
||||
<member name="M:S7.Net.Plc.Read(S7.Net.DataType,System.Int32,System.Int32,S7.Net.VarType,System.Int32,System.Byte)">
|
||||
<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).
|
||||
@@ -353,6 +353,7 @@
|
||||
<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>
|
||||
</member>
|
||||
<member name="M:S7.Net.Plc.Read(System.String)">
|
||||
@@ -520,13 +521,14 @@
|
||||
<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)">
|
||||
<member name="M:S7.Net.Plc.ParseBytes(S7.Net.VarType,System.Byte[],System.Int32,System.Byte)">
|
||||
<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>
|
||||
</member>
|
||||
<member name="M:S7.Net.Plc.VarTypeToByteLength(S7.Net.VarType,System.Int32)">
|
||||
@@ -542,6 +544,21 @@
|
||||
Releases all resources, disonnects from the plc and closes the socket
|
||||
</summary>
|
||||
</member>
|
||||
<member name="T:S7.Net.Types.Bit">
|
||||
<summary>
|
||||
Contains the conversion methods to convert Bit from S7 plc to C#.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:S7.Net.Types.Bit.FromByte(System.Byte,System.Byte)">
|
||||
<summary>
|
||||
Converts a Bit to bool
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:S7.Net.Types.Bit.ToBitArray(System.Byte[])">
|
||||
<summary>
|
||||
Converts an array of bytes to a BitArray
|
||||
</summary>
|
||||
</member>
|
||||
<member name="T:S7.Net.Types.Boolean">
|
||||
<summary>
|
||||
Contains the methods to read, set and reset bits inside bytes
|
||||
|
||||
Reference in New Issue
Block a user