Development Guide


Eine S7 App

  1. Verweis zum IPS7LnkNet.Advanced Namespace hinzufügen:
    using IPS7Lnk.Advanced;
  2. Eine Instanz der SimaticDevice Klasse mit der Adresse der Steuerung erzeugen:
    var device = new SimaticDevice("192.168.0.80");
  3. Verbindung zur Steuerung erstellen und öffnen:
    var connection = device.CreateConnection();
    connection.Open();
  4. Ihr Code zur Interaktion mit der Steuerung:
    // Your code to interact with the controller.
  5. Vor dem Beenden der Anwendung die Verbindung wieder trennen:
    connection.Close();
  6. Unter Verwendung des using Blocks sieht das dann so aus:
    using (var connection = device.CreateConnection()) {
        connection.Open();
        // Your code to interact with the controller.
    }

Adressierung

Die folgenden Typen kommen hierbei zum Einsatz: PlcAddress, PlcRawType, PlcOperand und PlcOperandType.

Unabhängig von der Art des Zugriffs, muss beschrieben werden, auf welchen Datenbereich man zugreifen möchte. Wo sich in der Steuerung die Daten befinden, auf die zugegriffen werden soll, wird anhand der PlcAddress des Datenbereichs festgelegt. Es besteht die Möglichkeit die PlcAddress als einfache Zeichenfolge (gemäß bekannter Addressierung in der SPS) oder über die API des SDKs zu konstruieren. Die im Folgenden gezeigten paarweisen Beispiele zeigen wie eine PlcAddress erstellt werden kann, um auf unterschiedliche Weise den gleichen Datenbereich zu adressieren.

  • Fünftes Datenwort im zehnten Datenbaustein:
    var a = PlcAddress.Parse("DB10.DBW 5");
    var b = new PlcAddress(PlcOperand.DataBlock(10), PlcRawType.Word, 12);
  • Erstes Bit im fünften Byte des zehnten Datenbausteins:
    var a = PlcAddress.Parse("DB10.DBX 5.1");
    var b = new PlcAddress(PlcOperand.DataBlock(10), PlcRawType.Bit, 5, 1);
  • Achtes Byte im Eingang:
    var a = PlcAddress.Parse("E8");
    var b = new PlcAddress(PlcOperand.Input, PlcRawType.Byte, 8);
  • Drittes Bit im neunten Byte des Merkers:
    var a = PlcAddress.Parse("M9.3");
    var b = new PlcAddress(PlcOperand.Flag, PlcRawType.Bit, 9, 3);

Zur Definition der PlcAddress über die Parse-Methode oder einen der Konstruktoren kann die Adressierung auch über den impliziten Cast-Operator der Klasse erfolgen. Unterstützt wird auch hier die Siemens- oder IEC-spezifische Adressierung.

PlcAddress address = "DB3.DBB 10";
PlcAddress address = "MB 5";
PlcAddress address = "AW 2";
PlcAddress address = "QW 2";

Die einer PlcAddress zugrundeliegende Zeichenkette der SPS Datenadresse kann über die ToString-Methode der PlcAddress Klasse abgerufen werden. Dabei besteht die Möglichkeit den gewünschten Operanden-Standard (Siemens oder IEC) anzugeben. Wird kein spezieller Standard angegeben wird immer vom Siemens Standard ausgegangen.

PlcAddress address = "DB3.DBB 10";
Console.WriteLine(address.ToString());                            // output: DB3.DBB 10
 
PlcAddress address = "MB 5";
Console.WriteLine(address.ToString());                            // output: MB 5
 
PlcAddress address = "AW 2";
Console.WriteLine(address.ToString());                            // output: AW 2
Console.WriteLine(address.ToString(PlcOperandStandard.IEC));      // output: QW 2
Console.WriteLine(address.ToString(PlcOperandStandard.Siemens));  // output: AW 2
 
PlcAddress address = "QW 2";
Console.WriteLine(address.ToString()); // output: AW 2
Console.WriteLine(address.ToString(PlcOperandStandard.IEC));      // output: QW 2
Console.WriteLine(address.ToString(PlcOperandStandard.Siemens));  // output: AW 2

Das hier gezeigte Vorgehen wird aus Gründen der Einfachheit in allen weiteren Code-Ausschnitten verwendet werden. Je nach Anwendungsfall kann die gewünschte Addressierungs-Form verwendet werden.

Werte lesen

Die folgenden Typen kommen hierbei zum Einsatz: SimaticDevice, PlcDeviceConnection und PlcAddress.

Zum Lesen eines Wertes aus einem bestimmten Datenbereich, kodiert im Format des entsprechenden SPS-Datentypen, wird eine der Datentyp-spezifischen Read-Methoden der PlcDeviceConnection verwendet. Zum Lesen der Daten besteht die Möglichkeit einen einzelnen Wert oder eine Folge von Werten (= ein Array) ab der angegebenen Adresse zu lesen. Soll ein Array gelesen werden, muss nach der Adresse zusätzlich noch die Anzahl der Elemente beim Aufruf der Read-Methode übergeben werden.

  • Einen einzelnen Int32-Wert lesen:
    int value = connection.ReadInt32("DB1.DBD 1");
  • Eine Folge von drei Int32-Werten lesen:
    int[] values = connection.ReadInt32("DB1.DBD 1", 3);

Abhängig davon, welches Format die PlcAddress aufweist und welcher SPS-Datentyp gelesen werden soll, werden dementsprechend viele Bytes gelesen. Der dabei gelesene SPS-Datentyp wird anschließend in die Form des gewünschten PC-Datentypen überführt.

Werte schreiben

Die folgenden Typen kommen hierbei zum Einsatz: SimaticDevice, PlcDeviceConnection und PlcAddress.

Zum Schreiben eines oder mehrerer Werte (= ein Array) in einen bestimmten Datenbereich, kodiert im Format des entsprechenden SPS-Datentypen, wird eine der Datentyp-spezifischen Write-Methoden der PlcDeviceConnection verwendet. Wird beim Schreiben ein Array anstelle eines einzelnen Wertes übergeben, dann werden alle Werte im Array in der selben Reihenfolge ab der angegebenen Adress geschrieben.

  • Einen einzelnen Int32-Wert schreiben:
    connection.WriteInt32("DB1.DBD 1", 123);
  • Eine Folge von drei Int32-Werten schreiben:
    connection.WriteInt32("DB1.DBD 1", 123, 456, 789);

Werte als SPS-Variablen

Die folgenden Typen kommen hierbei zum Einsatz: SimaticDevice, PlcDeviceConnection, PlcAddress, PlcInt32, PlcInt32Array, PlcBoolean, PlcBooleanArray und PlcString.

Häufig muss ein bestimmter Datenbereich mehrmals und an unterschiedlichen Stelle im Programmfluss gelesen oder geschrieben werden. Ändert sich dann der Datenbereich, in dem der Wert in der SPS steht, muss der gesamte Quellcode nach der alten Adresse durchsucht und entsprechend der neuen angepasst werden. Zudem ist nicht immer klar, welcher Wert sich hinter einer SPS Adresse eines bestimmten Datenbereichs verbirgt. Mit der von Hilfe PlcValue-Objekten können SPS-Variablen im Quellcode einmalig definiert und jederzeit eindeutig adressiert werden.

  • Eine einzelne Int32-Variable definieren und lesen:
    var speedVariable = new PlcInt32("DB1.DBD 1");
    var speed = connection.ReadValue(speedVariable);
  • Eine Int32-Array-Variable definieren und lesen:
    var coordinatesVariable = new PlcInt32Array("DB1.DBD 1", 3);
    var coordinates = connection.ReadValue(coordinatesVariable);
  • Eine einzelne Int32-Variable definieren und schreiben:
    var speedVariable = new PlcInt32("DB1.DBD 1", 123);
    connection.WriteValue(speedVariable);
     
    speedVariable.Value = 1200;
    connection.WriteValue(speedVariable);
  • Eine Int32-Array-Variable definieren und schreiben:
    var coordinatesVariable = new PlcInt32Array("DB1.DBD 1", 123, 456, 789);
    connection.WriteValue(coordinatesVariable);
     
    coordinatesVariable.Value[0] = 10;
    coordinatesVariable.Value[1] = 20;
    coordinatesVariable.Value[2] = 30;
    connection.WriteValue(coordinatesVariable);

Abhängig davon, welches Format die PlcAddress aufweist und welcher SPS-Datentyp geschrieben werden soll, werden dementsprechend viele Bytes geschrieben. Der dabei zu schreibende PC-Datentyp wird zuvor in die Form des gewünschten SPS-Datentypen überführt.

Da die Konsistenz der gelesenen oder geschriebenen Daten besonders wichtig ist, besteht die Möglichkeit auch mehrere SPS-Variablen gleichzeitig zu lesen oder zu schreiben. Die Mischung von verschiedenen PlcValue-Instanzen funktioniert an dieser Stelle genau so, als würde man nur Instanzen eines bestimmten PlcValue-Typen verwenden. Geht man zum Beispiel von folgenden Prozessabbild aus, sehen die entsprechenden Read-/Write-Zugriffe wie folgt aus.

var speedVariable = new PlcInt32("DB1.DBD 1");
var coordinatesVariable = new PlcInt32Array("DB2.DBD 1", 3);
var jobIsActiveVariable = new PlcBoolean("DB3.DBX 1.0");
var toolSetupVariable = new PlcBooleanArray("DB4.DBX 1.0", 5);
var operatorNameVariable = new PlcString("DB5.DBB 1", 32);

Das Lesen des Prozessabbilds könnte folgendermaßen aussehen:

connection.ReadValues(
        speedVariable,
        coordinatesVariable,
        jobIsActiveVariable,
        toolSetupVariable,
        operatorNameVariable);
 
Console.WriteLine($"Speed: {speedVariable.Value}");
Console.WriteLine($"Coordinates: {string.Join(",", coordinatesVariable.Value)}");
Console.WriteLine($"Job is Active: {jobIsActiveVariable.Value}");
Console.WriteLine($"Tool Setup: {string.Join(",", toolSetupVariable.Value)}");
Console.WriteLine($"Operator Name: {operatorNameVariable.Value}");

Das Schreiben des Prozessabbilds könnte folgendermaßen aussehen:

speedVariable.Value += 100;
coordinatesVariable.Value = new[] { 10, 20, 30 };
jobIsActiveVariable.Value = true;
toolSetupVariable.Value = new[] { false, true, true };
operatorNameVariable.Value = Environment.UserName;
 
connection.WriteValues(
        speedVariable,
        coordinatesVariable,
        jobIsActiveVariable,
        toolSetupVariable,
        operatorNameVariable);

Der Wert der Value-Eigenschaft der SPS-Variable kann über den Konstruktor der PlcValue-Klasse festgelegt und über die Value-Eigenschaft geändert werden. Der Wert, der im Konstruktor übergeben wird, kann dann als Initialwert verstanden werden. Wird die Value-Eigenschaft geändert, wird nicht automatisch der neue Werte in die Steuerung übertragen – es muss über ein explizierter WriteValue(s)-Aufruf durchgeführt werden.

Im den folgenden Abschnitten wird davon ausgegangen, dass in der Steuerung ein Prozessabbild existiert, welches dem (fiktiven) Datentypen „MillJob“ entspricht.
Die Struktur des Datentypen wird dabei wie folgt definiert:

MillJob
  .Input : int
  .Number : string
  .Output : int
  .RotationSpeed : int
  .ToolDiameter : float

Struktur definieren

Die folgenden Typen kommen hierbei zum Einsatz: PlcObject, PlcMemberAttribute und PlcMember.

Zur Definition der Struktur für den Zugriff auf strukturierte Daten wird die PlcObject Klasse abgeleitet. Bei der Ableitung werden dann für alle zu adressierenden Datenbereiche entsprechende Felder und/oder Eigenschaften definiert. Auf jedem Member, das einen Wert in der Steuerung repräsentiert muss dann das PlcMemberAttribute festgelegt werden. Über das Attribut wird dann der zugehörige Datenbereich adressiert. Handelt es sich um ein Array oder einen String-Wert, wird im Attribut zusätzlich die Anzahl der Elemente beziehungsweise die Länge des Strings angegeben.

Für die zuvor fiktiv definierte Struktur ergibt sich dann zum Beispiel folgende Implementierung als PlcObject:

public class MillJob : PlcObject
{
    [PlcMember("DB1.DBD 20")]
    public int Input;
 
    [PlcMember("DB1.DBB 1", Length = 16)]
    public string Number;
 
    [PlcMember("DB1.DBD 25")]
    public int Output;
 
    [PlcMember("DB1.DBD 30")]
    public int RotationSpeed;
 
    [PlcMember("DB1.DBW 40")]
    public float ToolDiameter;
}

Durch die Kombination der Adressierung der Prozessdaten über Felder und Eigenschaften können nicht-POCOs implementiert werden:

public class MachineData : PlcObject
{
    [PlcMember("DB1.DBX 100.0", Length = 7)]
    private bool[] toolConfigurations;
 
    public MachineData()
        : base()
    {
    }
 
    [PlcMember("DB1.DBB 120")]
    public DateTime EstimatedFinishDate { get; set; }
 
    [PlcMember("DB1.DBB 1", Length = 16)]
    public string JobNumber { get; set; }
 
    [PlcMember("DB1.DBD 100")]
    public int Speed { get; set; }
 
    [PlcMember("DB1.DBW 50")]
    public float Temperature { get; set; }
 
    [PlcMember("DB1.DBX 100.0")]
    public bool UseCuttingTool { get; set; }
 
    public bool IsToolConfigured(int toolIndex)
    {
        return this.toolConfigurations[toolIndex];
    }
}

Die zur Definition benötigten Informationen können entweder über das Handbuch der Steuerung oder vom verantwortlichen SPS-Entwickler bezogen werden.

Struktur lesen

Die folgenden Typen kommen hierbei zum Einsatz: SimaticDevice, PlcDeviceConnection und PlcObject.

Zum Lesen sturkturierter Daten über eine zuvor definierte Struktur wird die ReadObject-Methode der Verbindung verwendet:

MillJob job = connection.ReadObject<MillJob>();
 
Console.WriteLine("Input: {0}", job.Input);
Console.WriteLine("Number: {0}", job.Number);
Console.WriteLine("Output: {0}", job.Output);
Console.WriteLine("Rotation Speed: {0}", job.RotationSpeed);
Console.WriteLine("Total Diameter: {0}", job.ToolDiameter);

Die in der Struktur definierten Felder/Eigenschaften werden 1:1 in der Reihenfolge gelesen, in der diese definiert wurden.

Struktur schreiben

Die folgenden Typen kommen hierbei zum Einsatz: SimaticDevice, PlcDeviceConnection und PlcObject.

Zum Schreiben sturkturierter Daten über eine zuvor definierte Struktur wird die WriteObject-Methode der Verbindung verwendet:

MillJob job = new MillJob();
job.Input = 1;
job.Number = "MJ:100012";
job.RotationSpeed = 3500;
job.ToolDiameter = 12.8f;
job.Output = 3;
 
connection.WriteObject(job);

Die zum Zeitpunkt des Aufrufs in der Struktur enthaltenen Werte werden 1:1 in der Reihenfolge, in der die Felder/Eigenschaften definiert wurden, geschrieben.

Status der Verbindung(en)

Die folgenden Typen kommen hierbei zum Einsatz: PlcDeviceConnection, PlcDeviceConnectionState, PlcStatus und PlcNotifications.

Die Verwaltung der Verbindungen zu den einzelnen Steuerungen setzt voraus, dass der Zustand jeder Verbindung zu jeden Zeitpunkt bekannt ist. Zur Überwachung des Zustandes einer Verbindung können die Ereignisse Opening, Opened, Connecting, Connected, Disconnected, Closing, Closed und Faulted behandeln. Zusammenfassend für alle diese Ereignisse kann auch das StateChanged-Ereignis behandelt werden.

connection.StateChanged += HandleConnectionStateChanged;
 
private static void HandleConnectionStateChanged(
        object sender,
        PlcDeviceConnectionStateChangedEventArgs e)
{
    if (connection.State == PlcDeviceConnectionState.Connected) {
        // ...
    }
}

Weitere Informationen über den Zustand der Verbindung können über die Status-Eigenschaft der Verbindung abgefragt werden. Teil dieser Informationen ist vor allem das Ergebnis der zuletzt ausgeführten Operation (wie zum Beispiel der zuletzt addressierte SPS-Datentyp). Auch hier kann die Änderung des Status entsprechend behandelt werden.

PlcStatus status = connection.Status;
status.Changed += HandleConnectionStatusChanged;

Im passenden EventHandler können dann die Status-Informationen für eine benutzerdefinierte Protokollierung oder erweiterten Auswertung des Verbindungszustands verwendet werden.

private static void HandleConnectionStatusChanged(object sender, EventArgs e)
{
    var status = (PlcStatus)sender;
 
    Console.WriteLine(status.TimeStamp);
    Console.WriteLine("- Code=[{0}]", status.Code);
    Console.WriteLine("- Text=[{0}]", status.Text);
    Console.WriteLine("- Exception=[{0}]", status.Exception?.Message ?? "<none>");
}

Zusätzlich zu den Instanz-bezogenen Ereignissen können auch global alle Verbindungen überwacht werden. Hierzu gehört neben den bereit genannten Ereignissen auch ein ConnectionCreated-Ereignis welches das dynamische Hinzufügen von weiteren EventHandlern ermöglicht.

PlcNotifications.ConnectionCreated += HandleNotificationsConnectionCreated;
 
...
 
private static void HandleNotificationsConnectionCreated(
        object sender,
        PlcNotifications.PlcDeviceConnectionEventArgs e)
{
    var connection = e.Connection;
 
    if (...) {
        // ...
    }
}

Status des Zugriffs

Die folgenden Typen kommen hierbei zum Einsatz: PlcDeviceConnection, PlcNotifications und PlcStatus.

Ein Zugriff auf einen bestimmten Datenbereich kann aus mehreren Gründen fehlschlagen. Während ein Bereich entweder nicht (mehr) existiert kann es auch sein, dass die Startadresse gültig ist, jedoch das Datenende nicht länger dem erwarteten Ende entspricht. Weitere solche Situationen sind ungültige Daten, da gegebenenfalls kein Initialwert festgelegt wurde. Die Ursache für Probleme beim Zugriff auf die Datenbereiche kann schnell über entsprechende StatusCodes herausgefunden werden.

Werden für den Zugriff PlcValue-Instanzen verwendet, kann für jede SPS-Variable der Status geprüft werden.

var speedVariable = new PlcInt32("DB1.DBD 1");
connection.ReadValue(speedVariable);
 
if (speedVariable.Status.Code == PlcStatusCode.NoError) {
    // ...
}

Zusätzlich kann bis auf die Ebene des SPS-Datentypen der Status geprüft werden. Hierzu verwendet man die GetStatus-Methode der Verbindung. Weiter besteht die Möglichkeit die Auswertung einer Operation selbst in die Hände zu nehmen. Dadurch ist es möglich eine fehlgeschlagene Operation, die auch zu einer Ausnahme führen kann, selbst zu bewerten und als „in Ordnung“ zu deklarieren. Das ist zum Beispiel dann sinnvoll, wenn man eine Standard-Anwendung für die Steuerungen einer Anlage entwickelt, diese besitzen jedoch nicht die gleichen Datenbereiche, weshalb ein nicht adressierbarer Datenbereich auch ignoriert werden kann.

Zur benutzerdefinerten Auswertung muss eine benutzerdefinerte Methode in der statischen PlcNotifications Klasse eingetragen werden.

PlcNotifications.EvaluateStatus = EvaluateStatus;
 
...
 
private static bool EvaluateStatus(IPlcStatusProvider provider)
{
    if (provider is PlcDeviceConnection connection) {
        // ...
    }
    else if (provider is IPlcValue value) {
        // ...
    }
 
    // Fallback to "everything is okay".
    return true;
}

Die folgenden Typen kommen hierbei zum Einsatz: SimaticDevice, IPlcDeviceInfo, PlcBlockInfo und PlcOperand.

Gelegentlich sind die Geräte-Informationen der Steuerung entscheidend, um herauszufinden, ob man mit der richtigen Steuerung arbeitet und wo diese genau steht. Zum Abrufen der hierfür zur Verfügung stehenden Gerätedaten kann ein Instanz der IPlcDeviceInfo-Schnittstelle über die GetInfo-Methode der PlcDevice Klasse abgerufen werden. Die Instanz enthält dann alle bereitgestellten Gerätedaten.

var device = new SimaticDevice("192.168.0.80");
var deviceInfo = device.GetInfo();
 
if (deviceInfo.HasName)
    Console.WriteLine($"Name:         {deviceInfo.Name}");
 
if (deviceInfo.HasLocation)
    Console.WriteLine($"Location:     {deviceInfo.Location}");
 
if (deviceInfo.HasModuleName)
    Console.WriteLine($"Modul Name:   {deviceInfo.ModuleName}");
 
if (deviceInfo.HasModuleType)
    Console.WriteLine($"Modul Type:   {deviceInfo.ModuleType}");
 
if (deviceInfo.HasModuleSerial)
    Console.WriteLine($"Modul Serial: {deviceInfo.ModuleSerial}");
 
if (deviceInfo.HasPlantId)
    Console.WriteLine($"Plant ID:     {deviceInfo.PlantId}");
 
if (deviceInfo.HasTime)
    Console.WriteLine($"Time:         {deviceInfo.Time}");
 
if (deviceInfo.HasCopyright)
    Console.WriteLine($"Copyright:    {deviceInfo.Copyright}");

Zu beachten ist, dass nicht jede Steuerung alle hier gezeigten Geräteinformationen bereitstellt. Ob eine Information zur Verfügung steht kann über eine der Has-Eigenschaften geprüft werden.

Allgemein

Die folgenden Typen kommen hierbei zum Einsatz: PlcDevice, PlcDeviceConnection und PlcDeviceConnectionType.

Die Klassen PlcDevice und PlcDeviceConnection werden als Basisklassen der SimaticDevice und SimaticDeviceConnection verwendet. Dadurch erbt die Klasse SimaticDevice zum Beispiel die EndPoint-Eigenschaft zur Konfiguration des Endpunktes über den sich mit der Steuerung verbunden werden soll. Ebenso stellt die PlcDeviceConnection diverse Eigenschaften bereit. Teil dieser sind Eigenschaften zur Steuerung des Timeout-Verhaltens und der Abbrucherkennung.

Weitere spezifische Einstellungen sind vom verwendeten Provider (= PlcDevice Derivat) abhängig und können nach einen Cast auf den PlcDeviceConnection spezifische Typen entsprechend konfiguriert werden. Ein Beispiel ist die Konfiguration des entsprechenden Kommunikationskanals OP oder PG.

Gerätetypen

Die folgenden Typen kommen hierbei zum Einsatz: SimaticDevice, SimaticDeviceType und SimaticChannelType.

Das Framework versucht generell automatisch den Gerätetypen und die passende Kanalart für die Steuerung zu ermitteln. Je nach Art der verwendeten Steuerung und Aufbau des Netzes kann es jedoch notwendig sein manuell den Gerätetypen beziehungsweise die Kanalart festzulegen.

Endpunkt

Die folgenden Typen kommen hierbei zum Einsatz: SimaticDevice, IPDeviceEndPoint und SimaticDeviceType.

Generell genügt für den Zugriff entweder der DNS-Name oder die IP-Adresse der Steuerung. Je nach Art der Steuerung und Setup des Netzes kann es sein, dass zusätzlich noch die Rack- und die Slot-Nummer der Steuerung festgelegt werden müssen.

Lizenzierung

Das IP S7 LINK SDK kommt mit einer Testlizenz die je Anwendungsstart 30 Minuten uneingeschränkt zur Softwareentwicklung verwendet werden kann. Sollte diese Einschränkung ihre Evaluationsmöglichkeiten einschränken, besteht die Möglichkeit eine alternative Testlizenz bei uns zu beantragen. Fragen Sie einfach unseren Support (via support@traeger.de) oder lassen Sie sich gleich direkt von uns beraten und offene Fragen durch unsere Entwickler klären!

Nach Erhalt Ihres personalisierten Lizenzschlüssels zur Entwicklung mit IP S7 LINK muss dieser dem Framework mitgeteilt werden. Fügen Sie hierzu die folgende Codezeile in Ihre Anwendung ein, bevor Sie das erste Mal auf die SimaticDeviceConnection Klasse zugreifen. Ersetzen Sie hierbei <insert your license code here> durch den von uns erhaltenen Lizenzschlüssel.

IPS7LnkNet.Advanced.Licenser.LicenseKey = "<insert your license code here>";

Zudem erhalten Sie Informationen über die aktuell vom Framework verwendete Lizenz über die LicenseInfo Eigenschaft der IPS7Lnk.Advanced.Licenser Klasse. Das funktioniert wie folgt:

ILicenseInfo license = IPS7LnkNet.Advanced.Licenser.LicenseInfo;
 
if (license.IsExpired)
    Console.WriteLine("The IP S7 LINK SDK license is expired!");

Im Laufe der Entwicklung/Evaluation ist es häufig egal, ob gerade die Testlizenz oder bereits die erworbene Lizenz verwendet wird. Sobald aber die Anwendung in den produktiven Einsatz geht, ist es ärgerlich, wenn die Anwendung während der Ausführung aufgrund einer ungültigen Lizenz nicht mehr funktioniert. Aus diesem Grund empfehlen wir den folgenden Codeausschnitt in die Anwendung zu implementieren und diesen zumindest beim Start der Anwendung auszuführen:

#if DEBUG
    IPS7LnkNet.Advanced.Licenser.FailIfUnlicensed();
#else
    IPS7LnkNet.Advanced.Licenser.ThrowIfUnlicensed();
#endif

Weitere Informationen zur Lizenzierung, dem Erwerb oder anderen Fragen erhalten Sie direkt auf unserer Produktseite unter: www.traeger.de.