From 616dc1094c355725440a687fbba4d435a603bd6c Mon Sep 17 00:00:00 2001 From: Michael Croes Date: Fri, 4 Jun 2021 00:09:45 +0200 Subject: [PATCH] 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