From 0750ee006f2154c5a7ada5b00398ee135d2f085d Mon Sep 17 00:00:00 2001 From: Michael Croes Date: Wed, 2 Jun 2021 22:06:00 +0200 Subject: [PATCH 1/8] Change S7 200 remote TSAP to 10.01 --- S7.Net/Protocol/ConnectionRequest.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/S7.Net/Protocol/ConnectionRequest.cs b/S7.Net/Protocol/ConnectionRequest.cs index 64e2b5d..2231ccb 100644 --- a/S7.Net/Protocol/ConnectionRequest.cs +++ b/S7.Net/Protocol/ConnectionRequest.cs @@ -9,7 +9,7 @@ namespace S7.Net.Protocol byte[] bSend1 = { 3, 0, 0, 22, //TPKT 17, //COTP Header Length - 224, //Connect Request + 224, //Connect Request 0, 0, //Destination Reference 0, 46, //Source Reference 0, //Flags @@ -27,12 +27,12 @@ namespace S7.Net.Protocol switch (cpu) { case CpuType.S7200: - //S7200: Chr(193) & Chr(2) & Chr(16) & Chr(0) 'Eigener Tsap + // local bSend1[13] = 0x10; bSend1[14] = 0x00; - //S7200: Chr(194) & Chr(2) & Chr(16) & Chr(0) 'Fremder Tsap + // remote bSend1[17] = 0x10; - bSend1[18] = 0x00; + bSend1[18] = 0x01; break; case CpuType.Logo0BA8: // These values are taken from NodeS7, it's not verified if these are From fd9aeb5b3bf29ca3267ce79bbfd2493ba2608ad9 Mon Sep 17 00:00:00 2001 From: Michael Croes Date: Wed, 2 Jun 2021 23:03:06 +0200 Subject: [PATCH 2/8] Fix unit test for S7 200 --- S7.Net.UnitTest/ConnectionRequestTest.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/S7.Net.UnitTest/ConnectionRequestTest.cs b/S7.Net.UnitTest/ConnectionRequestTest.cs index 440a962..eff00e3 100644 --- a/S7.Net.UnitTest/ConnectionRequestTest.cs +++ b/S7.Net.UnitTest/ConnectionRequestTest.cs @@ -9,7 +9,7 @@ namespace S7.Net.UnitTest [TestMethod] public void Test_ConnectionRequest_S7_200() { - CollectionAssert.AreEqual(MakeConnectionRequest(16, 0, 16, 0), + CollectionAssert.AreEqual(MakeConnectionRequest(16, 0, 16, 1), ConnectionRequest.GetCOTPConnectionRequest(CpuType.S7200, 0, 0)); } From 70bc1499efc3688bfbae56b358cb6035202c1bcf Mon Sep 17 00:00:00 2001 From: Michael Croes Date: Wed, 2 Jun 2021 23:03:23 +0200 Subject: [PATCH 3/8] ConnectionRequestTest: Cleanup trailing whitespace --- S7.Net.UnitTest/ConnectionRequestTest.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/S7.Net.UnitTest/ConnectionRequestTest.cs b/S7.Net.UnitTest/ConnectionRequestTest.cs index eff00e3..6429d14 100644 --- a/S7.Net.UnitTest/ConnectionRequestTest.cs +++ b/S7.Net.UnitTest/ConnectionRequestTest.cs @@ -63,7 +63,7 @@ namespace S7.Net.UnitTest { 3, 0, 0, 22, //TPKT 17, //COTP Header Length - 224, //Connect Request + 224, //Connect Request 0, 0, //Destination Reference 0, 46, //Source Reference 0, //Flags From 616dc1094c355725440a687fbba4d435a603bd6c Mon Sep 17 00:00:00 2001 From: Michael Croes Date: Fri, 4 Jun 2021 00:09:45 +0200 Subject: [PATCH 4/8] Refactor TSAP related code --- S7.Net.UnitTest/ConnectionRequestTest.cs | 8 +-- S7.Net/Protocol/ConnectionRequest.cs | 83 ++++++++++++++---------- S7.Net/Protocol/Tsap.cs | 31 +++++++++ S7.Net/Protocol/TsapPair.cs | 30 +++++++++ 4 files changed, 113 insertions(+), 39 deletions(-) create mode 100644 S7.Net/Protocol/Tsap.cs create mode 100644 S7.Net/Protocol/TsapPair.cs diff --git a/S7.Net.UnitTest/ConnectionRequestTest.cs b/S7.Net.UnitTest/ConnectionRequestTest.cs index 440a962..f12fa16 100644 --- a/S7.Net.UnitTest/ConnectionRequestTest.cs +++ b/S7.Net.UnitTest/ConnectionRequestTest.cs @@ -49,11 +49,11 @@ namespace S7.Net.UnitTest [TestMethod] public void Test_ConnectionRequest_S7_1500() { - CollectionAssert.AreEqual(MakeConnectionRequest(0x10, 0x2, 3, 0), + CollectionAssert.AreEqual(MakeConnectionRequest(1, 0, 3, 0), ConnectionRequest.GetCOTPConnectionRequest(CpuType.S71500, 0, 0)); - CollectionAssert.AreEqual(MakeConnectionRequest(0x10, 0x2, 3, 1), + CollectionAssert.AreEqual(MakeConnectionRequest(1, 0, 3, 1), ConnectionRequest.GetCOTPConnectionRequest(CpuType.S71500, 0, 1)); - CollectionAssert.AreEqual(MakeConnectionRequest(0x10, 0x2, 3, 33), + CollectionAssert.AreEqual(MakeConnectionRequest(1, 0, 3, 33), ConnectionRequest.GetCOTPConnectionRequest(CpuType.S71500, 1, 1)); } @@ -63,7 +63,7 @@ namespace S7.Net.UnitTest { 3, 0, 0, 22, //TPKT 17, //COTP Header Length - 224, //Connect Request + 224, //Connect Request 0, 0, //Destination Reference 0, 46, //Source Reference 0, //Flags diff --git a/S7.Net/Protocol/ConnectionRequest.cs b/S7.Net/Protocol/ConnectionRequest.cs index 64e2b5d..83f568f 100644 --- a/S7.Net/Protocol/ConnectionRequest.cs +++ b/S7.Net/Protocol/ConnectionRequest.cs @@ -6,64 +6,77 @@ namespace S7.Net.Protocol { public static byte[] GetCOTPConnectionRequest(CpuType cpu, Int16 rack, Int16 slot) { + var tsapPair = GetDefaultTsapPair(cpu, rack, slot); + byte[] bSend1 = { 3, 0, 0, 22, //TPKT 17, //COTP Header Length - 224, //Connect Request + 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 + tsapPair.Local.FirstByte, tsapPair.Local.SecondByte, //Source TASP 194, //Parameter Code (dst-tasp) 2, //Parameter Length - 3, 0, //Destination TASP + tsapPair.Remote.FirstByte, tsapPair.Remote.SecondByte, //Destination TASP 192, //Parameter Code (tpdu-size) 1, //Parameter Length 10 //TPDU Size (2^10 = 1024) }; - switch (cpu) + return bSend1; + } + + /// + /// Builds a that can be used to connect to a PLC using the default connection + /// addresses. + /// + /// + /// The remote TSAP is constructed using new Tsap(0x03, (byte) ((rack << 5) | slot)). + /// + /// The CPU type of the PLC. + /// The rack of the PLC's network card. + /// The slot of the PLC's network card. + /// A TSAP pair that matches the given parameters. + /// The is invalid. + /// + /// -or- + /// + /// The parameter is greater than 15. + /// + /// -or- + /// + /// The parameter is greater than 15. + public static TsapPair GetDefaultTsapPair(CpuType cpuType, int rack, int slot) + { + if (rack > 0x0F) throw InvalidRackOrSlot(rack, nameof(rack)); + if (slot > 0x0F) throw InvalidRackOrSlot(slot, nameof(slot)); + + switch (cpuType) { 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; + return new TsapPair(new Tsap(0x10, 0x00), new Tsap(0x10, 0x00)); 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; + // The actual values are probably on a per-project basis + return new TsapPair(new Tsap(0x01, 0x00), new Tsap(0x01, 0x02)); case CpuType.S71200: + case CpuType.S71500: 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; + // Testing with S7 1500 shows only the remote TSAP needs to match. This might differ for other + // PLC types. + return new TsapPair(new Tsap(0x01, 0x00), new Tsap(0x03, (byte) ((rack << 5) | slot))); default: - throw new Exception("Wrong CPU Type Secified"); + throw new ArgumentOutOfRangeException(nameof(cpuType), "Invalid CPU Type specified"); } - return bSend1; + } + + private static ArgumentOutOfRangeException InvalidRackOrSlot(int value, string name) + { + return new ArgumentOutOfRangeException(name, + $"Invalid {name} value specified (decimal: {value}, hexadecimal: {value:X}), maximum value is 15 (decimal) or 0x0F (hexadecimal)."); } } } diff --git a/S7.Net/Protocol/Tsap.cs b/S7.Net/Protocol/Tsap.cs new file mode 100644 index 0000000..dc9d46c --- /dev/null +++ b/S7.Net/Protocol/Tsap.cs @@ -0,0 +1,31 @@ +namespace S7.Net.Protocol +{ + /// + /// Provides a representation of the Transport Service Access Point, or TSAP in short. TSAP's are used + /// to specify a client and server address. For most PLC types a default TSAP is available that allows + /// connection from any IP and can be calculated using the rack and slot numbers. + /// + public struct Tsap + { + /// + /// First byte of the TSAP. + /// + public byte FirstByte { get; set; } + + /// + /// Second byte of the TSAP. + /// + public byte SecondByte { get; set; } + + /// + /// Initializes a new instance of the class using the specified values. + /// + /// The first byte of the TSAP. + /// The second byte of the TSAP. + public Tsap(byte firstByte, byte secondByte) + { + FirstByte = firstByte; + SecondByte = secondByte; + } + } +} \ No newline at end of file diff --git a/S7.Net/Protocol/TsapPair.cs b/S7.Net/Protocol/TsapPair.cs new file mode 100644 index 0000000..0869b23 --- /dev/null +++ b/S7.Net/Protocol/TsapPair.cs @@ -0,0 +1,30 @@ +namespace S7.Net.Protocol +{ + /// + /// Implements a pair of TSAP addresses used to connect to a PLC. + /// + public class TsapPair + { + /// + /// The local . + /// + public Tsap Local { get; set; } + + /// + /// The remote + /// + public Tsap Remote { get; set; } + + /// + /// Initializes a new instance of the class using the specified local and + /// remote TSAP. + /// + /// The local TSAP. + /// The remote TSAP. + public TsapPair(Tsap local, Tsap remote) + { + Local = local; + Remote = remote; + } + } +} \ No newline at end of file From fcd61c1236c41041e5ce5d883dc375b8ad660f28 Mon Sep 17 00:00:00 2001 From: Michael Croes Date: Fri, 4 Jun 2021 21:46:42 +0200 Subject: [PATCH 5/8] Add CpuType.S7200Smart --- S7.Net/Enums.cs | 5 +++++ S7.Net/Protocol/ConnectionRequest.cs | 1 + 2 files changed, 6 insertions(+) diff --git a/S7.Net/Enums.cs b/S7.Net/Enums.cs index 436d94b..fc412d3 100644 --- a/S7.Net/Enums.cs +++ b/S7.Net/Enums.cs @@ -15,6 +15,11 @@ /// Logo0BA8 = 1, + /// + /// S7 200 Smart + /// + S7200Smart = 2, + /// /// S7 300 cpu type /// diff --git a/S7.Net/Protocol/ConnectionRequest.cs b/S7.Net/Protocol/ConnectionRequest.cs index 83f568f..9c6c5bb 100644 --- a/S7.Net/Protocol/ConnectionRequest.cs +++ b/S7.Net/Protocol/ConnectionRequest.cs @@ -61,6 +61,7 @@ namespace S7.Net.Protocol case CpuType.Logo0BA8: // The actual values are probably on a per-project basis return new TsapPair(new Tsap(0x01, 0x00), new Tsap(0x01, 0x02)); + case CpuType.S7200Smart: case CpuType.S71200: case CpuType.S71500: case CpuType.S7300: From 6465e3c8c7ae7200ad9954d1594915540a28f0e6 Mon Sep 17 00:00:00 2001 From: Michael Croes Date: Fri, 4 Jun 2021 21:58:15 +0200 Subject: [PATCH 6/8] Move GetDefaultTsapPair to TsapPair class --- S7.Net/Protocol/ConnectionRequest.cs | 53 +--------------------- S7.Net/Protocol/TsapPair.cs | 68 +++++++++++++++++++++++++++- 2 files changed, 68 insertions(+), 53 deletions(-) diff --git a/S7.Net/Protocol/ConnectionRequest.cs b/S7.Net/Protocol/ConnectionRequest.cs index 9c6c5bb..19b441c 100644 --- a/S7.Net/Protocol/ConnectionRequest.cs +++ b/S7.Net/Protocol/ConnectionRequest.cs @@ -6,7 +6,7 @@ namespace S7.Net.Protocol { public static byte[] GetCOTPConnectionRequest(CpuType cpu, Int16 rack, Int16 slot) { - var tsapPair = GetDefaultTsapPair(cpu, rack, slot); + var tsapPair = TsapPair.GetDefaultTsapPair(cpu, rack, slot); byte[] bSend1 = { 3, 0, 0, 22, //TPKT @@ -28,56 +28,5 @@ namespace S7.Net.Protocol return bSend1; } - - /// - /// Builds a that can be used to connect to a PLC using the default connection - /// addresses. - /// - /// - /// The remote TSAP is constructed using new Tsap(0x03, (byte) ((rack << 5) | slot)). - /// - /// The CPU type of the PLC. - /// The rack of the PLC's network card. - /// The slot of the PLC's network card. - /// A TSAP pair that matches the given parameters. - /// The is invalid. - /// - /// -or- - /// - /// The parameter is greater than 15. - /// - /// -or- - /// - /// The parameter is greater than 15. - public static TsapPair GetDefaultTsapPair(CpuType cpuType, int rack, int slot) - { - if (rack > 0x0F) throw InvalidRackOrSlot(rack, nameof(rack)); - if (slot > 0x0F) throw InvalidRackOrSlot(slot, nameof(slot)); - - switch (cpuType) - { - case CpuType.S7200: - return new TsapPair(new Tsap(0x10, 0x00), new Tsap(0x10, 0x00)); - case CpuType.Logo0BA8: - // The actual values are probably on a per-project basis - return new TsapPair(new Tsap(0x01, 0x00), new Tsap(0x01, 0x02)); - case CpuType.S7200Smart: - case CpuType.S71200: - case CpuType.S71500: - case CpuType.S7300: - case CpuType.S7400: - // Testing with S7 1500 shows only the remote TSAP needs to match. This might differ for other - // PLC types. - return new TsapPair(new Tsap(0x01, 0x00), new Tsap(0x03, (byte) ((rack << 5) | slot))); - default: - throw new ArgumentOutOfRangeException(nameof(cpuType), "Invalid CPU Type specified"); - } - } - - private static ArgumentOutOfRangeException InvalidRackOrSlot(int value, string name) - { - return new ArgumentOutOfRangeException(name, - $"Invalid {name} value specified (decimal: {value}, hexadecimal: {value:X}), maximum value is 15 (decimal) or 0x0F (hexadecimal)."); - } } } diff --git a/S7.Net/Protocol/TsapPair.cs b/S7.Net/Protocol/TsapPair.cs index 0869b23..4a329d3 100644 --- a/S7.Net/Protocol/TsapPair.cs +++ b/S7.Net/Protocol/TsapPair.cs @@ -1,4 +1,6 @@ -namespace S7.Net.Protocol +using System; + +namespace S7.Net.Protocol { /// /// Implements a pair of TSAP addresses used to connect to a PLC. @@ -26,5 +28,69 @@ Local = local; Remote = remote; } + + /// + /// Builds a that can be used to connect to a PLC using the default connection + /// addresses. + /// + /// + /// The remote TSAP is constructed using new Tsap(0x03, (byte) ((rack << 5) | slot)). + /// + /// The CPU type of the PLC. + /// The rack of the PLC's network card. + /// The slot of the PLC's network card. + /// A TSAP pair that matches the given parameters. + /// The is invalid. + /// + /// -or- + /// + /// The parameter is less than 0. + /// + /// -or- + /// + /// The parameter is greater than 15. + /// + /// -or- + /// + /// The parameter is less than 0. + /// + /// -or- + /// + /// The parameter is greater than 15. + public static TsapPair GetDefaultTsapPair(CpuType cpuType, int rack, int slot) + { + if (rack < 0) throw InvalidRackOrSlot(rack, nameof(rack), "minimum", 0); + if (rack > 0x0F) throw InvalidRackOrSlot(rack, nameof(rack), "maximum", 0x0F); + + if (slot < 0) throw InvalidRackOrSlot(slot, nameof(slot), "minimum", 0); + if (slot > 0x0F) throw InvalidRackOrSlot(slot, nameof(slot), "maximum", 0x0F); + + switch (cpuType) + { + case CpuType.S7200: + return new TsapPair(new Tsap(0x10, 0x00), new Tsap(0x10, 0x00)); + case CpuType.Logo0BA8: + // The actual values are probably on a per-project basis + return new TsapPair(new Tsap(0x01, 0x00), new Tsap(0x01, 0x02)); + case CpuType.S7200Smart: + case CpuType.S71200: + case CpuType.S71500: + case CpuType.S7300: + case CpuType.S7400: + // Testing with S7 1500 shows only the remote TSAP needs to match. This might differ for other + // PLC types. + return new TsapPair(new Tsap(0x01, 0x00), new Tsap(0x03, (byte) ((rack << 5) | slot))); + default: + throw new ArgumentOutOfRangeException(nameof(cpuType), "Invalid CPU Type specified"); + } + } + + private static ArgumentOutOfRangeException InvalidRackOrSlot(int value, string name, string extrema, + int extremaValue) + { + return new ArgumentOutOfRangeException(name, + $"Invalid {name} value specified (decimal: {value}, hexadecimal: {value:X}), {extrema} value " + + $"is {extremaValue} (decimal) or {extremaValue:X} (hexadecimal)."); + } } } \ No newline at end of file From 2fae2c01d5d60624020559fe16709e7be24c3edc Mon Sep 17 00:00:00 2001 From: Michael Croes Date: Fri, 4 Jun 2021 22:25:05 +0200 Subject: [PATCH 7/8] Add TsapPair support to PLC Add support for custom addressing by supplying a TsapPair to the PLC. CPU, Rack and Slot properties are still present to preserve backwards compatibility and to support alternate functionality based on the PLC type. --- S7.Net.UnitTest/ConnectionRequestTest.cs | 26 ++++----- S7.Net/PLC.cs | 67 +++++++++++++++++------- S7.Net/PlcAsynchronous.cs | 2 +- S7.Net/Protocol/ConnectionRequest.cs | 8 +-- 4 files changed, 63 insertions(+), 40 deletions(-) diff --git a/S7.Net.UnitTest/ConnectionRequestTest.cs b/S7.Net.UnitTest/ConnectionRequestTest.cs index f12fa16..acd2ee0 100644 --- a/S7.Net.UnitTest/ConnectionRequestTest.cs +++ b/S7.Net.UnitTest/ConnectionRequestTest.cs @@ -10,51 +10,51 @@ namespace S7.Net.UnitTest public void Test_ConnectionRequest_S7_200() { CollectionAssert.AreEqual(MakeConnectionRequest(16, 0, 16, 0), - ConnectionRequest.GetCOTPConnectionRequest(CpuType.S7200, 0, 0)); + ConnectionRequest.GetCOTPConnectionRequest(TsapPair.GetDefaultTsapPair(CpuType.S7200, 0, 0))); } [TestMethod] public void Test_ConnectionRequest_S7_300() { CollectionAssert.AreEqual(MakeConnectionRequest(1, 0, 3, 0), - ConnectionRequest.GetCOTPConnectionRequest(CpuType.S7300, 0, 0)); + ConnectionRequest.GetCOTPConnectionRequest(TsapPair.GetDefaultTsapPair(CpuType.S7300, 0, 0))); CollectionAssert.AreEqual(MakeConnectionRequest(1, 0, 3, 1), - ConnectionRequest.GetCOTPConnectionRequest(CpuType.S7300, 0, 1)); + ConnectionRequest.GetCOTPConnectionRequest(TsapPair.GetDefaultTsapPair(CpuType.S7300, 0, 1))); CollectionAssert.AreEqual(MakeConnectionRequest(1, 0, 3, 33), - ConnectionRequest.GetCOTPConnectionRequest(CpuType.S7300, 1, 1)); + ConnectionRequest.GetCOTPConnectionRequest(TsapPair.GetDefaultTsapPair(CpuType.S7300, 1, 1))); } [TestMethod] public void Test_ConnectionRequest_S7_400() { CollectionAssert.AreEqual(MakeConnectionRequest(1, 0, 3, 0), - ConnectionRequest.GetCOTPConnectionRequest(CpuType.S7400, 0, 0)); + ConnectionRequest.GetCOTPConnectionRequest(TsapPair.GetDefaultTsapPair(CpuType.S7400, 0, 0))); CollectionAssert.AreEqual(MakeConnectionRequest(1, 0, 3, 1), - ConnectionRequest.GetCOTPConnectionRequest(CpuType.S7400, 0, 1)); + ConnectionRequest.GetCOTPConnectionRequest(TsapPair.GetDefaultTsapPair(CpuType.S7400, 0, 1))); CollectionAssert.AreEqual(MakeConnectionRequest(1, 0, 3, 33), - ConnectionRequest.GetCOTPConnectionRequest(CpuType.S7400, 1, 1)); + ConnectionRequest.GetCOTPConnectionRequest(TsapPair.GetDefaultTsapPair(CpuType.S7400, 1, 1))); } [TestMethod] public void Test_ConnectionRequest_S7_1200() { CollectionAssert.AreEqual(MakeConnectionRequest(1, 0, 3, 0), - ConnectionRequest.GetCOTPConnectionRequest(CpuType.S71200, 0, 0)); + ConnectionRequest.GetCOTPConnectionRequest(TsapPair.GetDefaultTsapPair(CpuType.S71200, 0, 0))); CollectionAssert.AreEqual(MakeConnectionRequest(1, 0, 3, 1), - ConnectionRequest.GetCOTPConnectionRequest(CpuType.S71200, 0, 1)); + ConnectionRequest.GetCOTPConnectionRequest(TsapPair.GetDefaultTsapPair(CpuType.S71200, 0, 1))); CollectionAssert.AreEqual(MakeConnectionRequest(1, 0, 3, 33), - ConnectionRequest.GetCOTPConnectionRequest(CpuType.S71200, 1, 1)); + ConnectionRequest.GetCOTPConnectionRequest(TsapPair.GetDefaultTsapPair(CpuType.S71200, 1, 1))); } [TestMethod] public void Test_ConnectionRequest_S7_1500() { CollectionAssert.AreEqual(MakeConnectionRequest(1, 0, 3, 0), - ConnectionRequest.GetCOTPConnectionRequest(CpuType.S71500, 0, 0)); + ConnectionRequest.GetCOTPConnectionRequest(TsapPair.GetDefaultTsapPair(CpuType.S71500, 0, 0))); CollectionAssert.AreEqual(MakeConnectionRequest(1, 0, 3, 1), - ConnectionRequest.GetCOTPConnectionRequest(CpuType.S71500, 0, 1)); + ConnectionRequest.GetCOTPConnectionRequest(TsapPair.GetDefaultTsapPair(CpuType.S71500, 0, 1))); CollectionAssert.AreEqual(MakeConnectionRequest(1, 0, 3, 33), - ConnectionRequest.GetCOTPConnectionRequest(CpuType.S71500, 1, 1)); + ConnectionRequest.GetCOTPConnectionRequest(TsapPair.GetDefaultTsapPair(CpuType.S71500, 1, 1))); } private static byte[] MakeConnectionRequest(byte sourceTsap1, byte sourceTsap2, byte destTsap1, byte destTsap2) diff --git a/S7.Net/PLC.cs b/S7.Net/PLC.cs index 6180ad5..5ec5618 100644 --- a/S7.Net/PLC.cs +++ b/S7.Net/PLC.cs @@ -15,6 +15,11 @@ namespace S7.Net /// public partial class Plc : IDisposable { + /// + /// The default port for the S7 protocol. + /// + public const int DefaultPort = 102; + private readonly TaskQueue queue = new TaskQueue(); private const int CONNECTION_TIMED_OUT_ERROR_CODE = 10060; @@ -36,6 +41,11 @@ namespace S7.Net /// public int Port { get; } + /// + /// The TSAP addresses used during the connection request. + /// + public TsapPair TsapPair { get; set; } + /// /// CPU type of the PLC /// @@ -108,25 +118,14 @@ namespace S7.Net /// /// CpuType of the PLC (select from the enum) /// Ip address of the PLC - /// Port address of the PLC, default 102 /// rack of the PLC, usually it's 0, but check in the hardware configuration of Step7 or TIA portal /// 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. - public Plc(CpuType cpu, string ip, int port, Int16 rack, Int16 slot) + public Plc(CpuType cpu, string ip, Int16 rack, Int16 slot) + : this(cpu, ip, DefaultPort, rack, slot) { - if (!Enum.IsDefined(typeof(CpuType), cpu)) - throw new ArgumentException($"The value of argument '{nameof(cpu)}' ({cpu}) is invalid for Enum type '{typeof(CpuType).Name}'.", nameof(cpu)); - - if (string.IsNullOrEmpty(ip)) - throw new ArgumentException("IP address must valid.", nameof(ip)); - - CPU = cpu; - IP = ip; - Port = port; - Rack = rack; - Slot = slot; - MaxPDUSize = 240; } + /// /// 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. @@ -135,23 +134,51 @@ namespace S7.Net /// /// CpuType of the PLC (select from the enum) /// Ip address of the PLC + /// Port number used for the connection, default 102. /// rack of the PLC, usually it's 0, but check in the hardware configuration of Step7 or TIA portal /// 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. - public Plc(CpuType cpu, string ip, Int16 rack, Int16 slot) + public Plc(CpuType cpu, string ip, int port, Int16 rack, Int16 slot) + : this(ip, port, TsapPair.GetDefaultTsapPair(cpu, rack, slot)) { if (!Enum.IsDefined(typeof(CpuType), cpu)) - throw new ArgumentException($"The value of argument '{nameof(cpu)}' ({cpu}) is invalid for Enum type '{typeof(CpuType).Name}'.", nameof(cpu)); + throw new ArgumentException( + $"The value of argument '{nameof(cpu)}' ({cpu}) is invalid for Enum type '{typeof(CpuType).Name}'.", + nameof(cpu)); + CPU = cpu; + Rack = rack; + Slot = slot; + } + + /// + /// 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. + /// + /// Ip address of the PLC + /// The TSAP addresses used for the connection request. + public Plc(string ip, TsapPair tsapPair) : this(ip, DefaultPort, tsapPair) + { + } + + /// + /// Creates a PLC object with all the parameters needed for connections. Use this constructor + /// if you want to manually override the TSAP addresses used during the connection request. + /// + /// Ip address of the PLC + /// Port number used for the connection, default 102. + /// The TSAP addresses used for the connection request. + public Plc(string ip, int port, TsapPair tsapPair) + { if (string.IsNullOrEmpty(ip)) throw new ArgumentException("IP address must valid.", nameof(ip)); - CPU = cpu; IP = ip; - Port = 102; - Rack = rack; - Slot = slot; + Port = port; MaxPDUSize = 240; + TsapPair = tsapPair; } /// diff --git a/S7.Net/PlcAsynchronous.cs b/S7.Net/PlcAsynchronous.cs index c7a5868..030cc3d 100644 --- a/S7.Net/PlcAsynchronous.cs +++ b/S7.Net/PlcAsynchronous.cs @@ -60,7 +60,7 @@ namespace S7.Net private async Task RequestConnection(Stream stream, CancellationToken cancellationToken) { - var requestData = ConnectionRequest.GetCOTPConnectionRequest(CPU, Rack, Slot); + var requestData = ConnectionRequest.GetCOTPConnectionRequest(TsapPair); var response = await NoLockRequestTpduAsync(stream, requestData, cancellationToken).ConfigureAwait(false); if (response.PDUType != COTP.PduType.ConnectionConfirmed) diff --git a/S7.Net/Protocol/ConnectionRequest.cs b/S7.Net/Protocol/ConnectionRequest.cs index 19b441c..9dbd396 100644 --- a/S7.Net/Protocol/ConnectionRequest.cs +++ b/S7.Net/Protocol/ConnectionRequest.cs @@ -1,13 +1,9 @@ -using System; - -namespace S7.Net.Protocol +namespace S7.Net.Protocol { internal static class ConnectionRequest { - public static byte[] GetCOTPConnectionRequest(CpuType cpu, Int16 rack, Int16 slot) + public static byte[] GetCOTPConnectionRequest(TsapPair tsapPair) { - var tsapPair = TsapPair.GetDefaultTsapPair(cpu, rack, slot); - byte[] bSend1 = { 3, 0, 0, 22, //TPKT 17, //COTP Header Length From 677d2941e1ac0b81af660a362f495440d8806f85 Mon Sep 17 00:00:00 2001 From: Michael Croes Date: Sun, 6 Jun 2021 22:33:12 +0200 Subject: [PATCH 8/8] Apply S7 200 TSAP change to relocated code --- S7.Net/Protocol/TsapPair.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/S7.Net/Protocol/TsapPair.cs b/S7.Net/Protocol/TsapPair.cs index 4a329d3..e54fc32 100644 --- a/S7.Net/Protocol/TsapPair.cs +++ b/S7.Net/Protocol/TsapPair.cs @@ -68,7 +68,7 @@ namespace S7.Net.Protocol switch (cpuType) { case CpuType.S7200: - return new TsapPair(new Tsap(0x10, 0x00), new Tsap(0x10, 0x00)); + return new TsapPair(new Tsap(0x10, 0x00), new Tsap(0x10, 0x01)); case CpuType.Logo0BA8: // The actual values are probably on a per-project basis return new TsapPair(new Tsap(0x01, 0x00), new Tsap(0x01, 0x02));