Development Guide


A S7 App

  1. Add reference to the IPS7LnkNet.Advanced Namespace:
    Imports IPS7Lnk.Advanced
  2. Create an instance of the SimaticDevice class with the address of the controller:
    Dim device = New SimaticDevice("192.168.0.80")
  3. Build and open a connection to the controller:
    Dim connection = device.CreateConnection()
    connection.Open()
  4. Your code to interact with the controller:
    ' Your code to interact with the controller.
  5. Close the connection before closing the application:
    connection.Close()
  6. Using the using block this looks as follows:
    Using connection = device.CreateConnection()
        connection.Open()
        ' Your code to interact with the controller.
    End Using

Addressing

The following types are used: PlcAddress, PlcRawType, PlcOperand and PlcOperandType.

Regardless of the type of access, it must be described which data area you want to access. The PlcAddress of the data area determines where the data to be accessed is located in the controller. It is possible to construct the PlcAddress as a simple string (according to know addressing in the PLC) or via the API of the SDK. The paired examples below show how a PlcAddress can be created to address the same data in different ways.

  • Fifth data word in the tenth data block:
    Dim a = PlcAddress.Parse("DB10.DBW 5")
    Dim b = New PlcAddress(PlcOperand.DataBlock(10), PlcRawType.Word, 12)
  • First bit in the fifth byte of the tenth data block:
    Dim a = PlcAddress.Parse("DB10.DBX 5.1")
    Dim b = New PlcAddress(PlcOperand.DataBlock(10), PlcRawType.Bit, 5, 1)
  • Eighth byte in the input:
    Dim a = PlcAddress.Parse("E8")
    Dim b = New PlcAddress(PlcOperand.Input, PlcRawType.Byte, 8)
  • Third bit in the ninth byte of the flag:
    Dim a = PlcAddress.Parse("M9.3")
    Dim b = New PlcAddress(PlcOperand.Flag, PlcRawType.Bit, 9, 3)

To define the PlcAddress using the Parse-method or one of the constructors, the addressing can also be done using the implicant cast operator of the class. Here the Siemens or IEC-specific addressing is also supported.

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

The character string of the PLC data address on which a PlcAddress is based on can be called up using the ToString method of the PlcAddress class. It is possible to specify the desired operand standard (Siemens or IEC).

If no special standard is specified, the Siemens standard is always used.

Dim address As PlcAddress = "DB3.DBB 10"
Console.WriteLine(address.ToString())                            ' output: DB3.DBB 10
 
Dim address As PlcAddress = "MB 5"
Console.WriteLine(address.ToString())                            ' output: MB 5
 
Dim address As PlcAddress = "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
 
Dim address As PlcAddress = "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

The procedure shown here will be used in all other code sections for the sake of simplicity. Depending on the application, the desired addressing form can be used.

Reading Values

The following types are used: SimaticDevice, PlcDeviceConnection and PlcAddress.

One of the data type-specific read methods of the

PlcDeviceConnection</oem> is used to read a value from a specific data area, coded in the format of the corresponding PLC data type. To read the data it is possible to read a single value or a sequence of values (=an array) from the specified address. If an array is to be read, the number of elements must also be passed after the address when the read method is called.

  • Read a single Int32-value:
    Dim value As Integer = connection.ReadInt32("DB1.DBD 1")
  • Read a sequence of three Int32-values:
    Dim values As Integer() = connection.ReadInt32("DB1.DBD 1", 3)

Depending on the format of the PlcAddress and the PLC data type to be read, many bytes are read accordingly. The read PLC data type is then converted into the form of the desired PC data type. </panel>

Writing Values

The following types are used: SimaticDevice, PlcDeviceConnection and PlcAddress.

To write one or more values (= an array) into a specific data area, coded in the format of the corresponding PLC data type, one of the data type-specific write methods of the

PlcDeviceConnection

is used. If an array is passed instead of a single value during writing, all values in the array are written in the same order from the specified address.

  • Write a single Int32-value:
    connection.WriteInt32("DB1.DBD 1", 123)
  • Write a sequence of three Int32-values:
    connection.WriteInt32("DB1.DBD 1", 123, 456, 789)

Values as PLC variables

Often a certain data area has to be read or written several times and at different points in the program flow. If the data in which the value is stored in die PLC then changes, the entire source code must be searched for the old address and adapted accordingly to the new one. In addition, it is not always clear what value is hidden behind a PLC address of a certain data area. With the help of PlcValue objects, PLC variables can be defined one in the source code and uniquely addressed in any time.

  • Define and read a single Int32-variable:
    Dim speedVariable = New PlcInt32("DB1.DBD 1")
    Dim speed = connection.ReadValue(speedVariable)
  • Define and read an Int32-array variable:
    Dim coordinatesVariable = New PlcInt32Array("DB1.DBD 1", 3)
    Dim coordinates = connection.ReadValue(coordinatesVariable)
  • Define and write a single Int32-variable:
    Dim speedVariable = New PlcInt32("DB1.DBD 1", 123)
    connection.WriteValue(speedVariable)
     
    speedVariable.Value = 1200
    connection.WriteValue(speedVariable)
  • Define and write an Int32-array variable:
    Dim 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)

Depending on the format of the PlcAddress and the PLC data type to be written, many bytes are written accordingly. The PC data type to be written is first converted into the desired PLC data type.

Since the consistency of the read or written data is particularly important, it is also possible to read or write several PLC variables at the same time. At this point, the mix of different PlcValue instances works exactly as if you were only using instances of a certain PlcValue type. Assuming, for example, the following process image, the corresponding read / write accesses look as follows.

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

Reading the process image could look like this:

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}")

The process image could be written as follows:

speedVariable.Value += 100
coordinatesVariable.Value = {10, 20, 30}
jobIsActiveVariable.Value = True
toolSetupVariable.Value = {False, True, True}
operatorNameVariable.Value = Environment.UserName
 
connection.WriteValues( _
        speedVariable, _
        coordinatesVariable, _
        jobIsActiveVariable, _
        toolSetupVariable, _
        operatorNameVariable)

The value of the value property of the PLC variable can be set using the constructor of the PlcValue class and changed using the value property. The value that is passed in the constructor can then be understood as a initial value. If the value property is changed, the new value is not automatically transferred to the controller - it must be carried out via an explicit WriteValue call.

The following sections assume that there is a process image in the controller that corresponds to the (fictitious) data type “MillJob”. The structure of the data type is defined as follows:

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

Define Structure

The following types are used: PlcObject, PlcMemberAttribute and PlcMember.

The PlcObject class is derived to define the structure for access to structured data. In the derivation, corresponding fields and / or properties are then defined for all data areas to be addressed. The PlcMemberAttribute must then be set on each member that represents a value in the controller. The associated data area is then addressed via the attribute. If it is an array or a string value, the attribute also specifies the number of elements or the length of the string.

For the previously fictionally defined structure for example, the following implementation results as a PlcObjekt:

Public Class MillJob
    Inherits PlcObject
    <PlcMember("DB1.DBD 20")>
    Public Input As Integer
 
    <PlcMember("DB1.DBB 1", Length:=16)>
    Public Number As String
 
    <PlcMember("DB1.DBD 25")>
    Public Output As Integer
 
    <PlcMember("DB1.DBD 30")>
    Public RotationSpeed As Integer
 
    <PlcMember("DB1.DBW 40")>
    Public ToolDiameter As Single
End Class

By combining the addressing of the process data via fields and properties, non-POCOs can be implemented:

Public Class MachineData
    Inherits PlcObject
    <PlcMember("DB1.DBX 100.0", Length:=7)>
    Private toolConfigurations As Boolean()
 
    Public Sub New()
        MyBase.New()
    End Sub
 
    <PlcMember("DB1.DBB 120")>
    Public Property EstimatedFinishDate As DateTime
 
    <PlcMember("DB1.DBB 1", Length:=16)>
    Public Property JobNumber As String
 
    <PlcMember("DB1.DBD 100")>
    Public Property Speed As Integer
 
    <PlcMember("DB1.DBW 50")>
    Public Property Temperature As Single
 
    <PlcMember("DB1.DBX 100.0")>
    Public Property UseCuttingTool As Boolean
 
    Public Function IsToolConfigured(ByVal toolIndex As Integer) As Boolean
        Return Me.toolConfigurations(toolIndex)
    End Function
End Class

The information required for the definition can either be obtained from the controller manual or from the responsible PLC developer.

Read Structure

The following types are used: SimaticDevice, PlcDeviceConnection and PlcObject.

The ReadObject method of the connection is used to read structured data via a previously defined structure:

Dim job As MillJob = connection.ReadObject(Of 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)

The fields / properties defined in the structure are read 1:1 in the order in which they were defined.

Write Structure

The following types are used: SimaticDevice, PlcDeviceConnection and PlcObject.

The WriteObject method of the connection is used to write structured data via a previously defined structure:

Dim job As MillJob = New MillJob()
job.Input = 1
job.Number = "MJ:100012"
job.RotationSpeed = 3500
job.ToolDiameter = 12.8F
job.Output = 3
 
connection.WriteObject(job)

The values contained in the structure at the time of the call are written 1:1 in the order in which the fields / properties were defined.

Connection(s) status

The management of the connections to the individual controllers presupposes that the status of each connection is known at all times. To monitor the status of a connection, the events Opening, Opened, Connecting, Connected, Disconnected, Closing, Closed and Faulted can be handled. In summary, the StateChanged event can also be handled for all of these events.

AddHandler connection.StateChanged, AddressOf HandleConnectionStateChanged
 
Private Shared Sub HandleConnectionStateChanged( _
        ByVal sender As Object, _
        ByVal e As PlcDeviceConnectionStateChangedEventArgs)
    If connection.State = PlcDeviceConnectionState.Connected Then
        ' ...
    End If
End Sub

Further information about the status of the connection can be queried via the status property of the connection. Part of this information is primarily the result of the last operation performed (such as the last addressed PLC data type). Here the change in status can be also treated accordingly.

Dim status As PlcStatus = connection.Status
status.Changed += AddressOf HandleConnectionStatusChanged

In the appropriate EventHandler, the status information can then be used for user-defined logging or extended evaluation of the connection status.

Private Shared Sub HandleConnectionStatusChanged(ByVal sender As Object, ByVal e As EventArgs)
    Dim status = CType(sender, PlcStatus)
 
    Console.WriteLine(status.TimeStamp)
    Console.WriteLine("- Code=[{0}]", status.Code)
    Console.WriteLine("- Text=[{0}]", status.Text)
    Console.WriteLine("- Exception=[{0}]", If(status.Exception?.Message, "<none>"))
End Sub

In addition to the instance-related events, all connections can also be monitored globally. Furthermore to the already mentioned events, this also includes a ConnectionCreated event which enables the dynamic addition of further event handlers.

PlcNotifications.ConnectionCreated += AddressOf HandleNotificationsConnectionCreated
 
...
 
Private Shared Sub HandleNotificationsConnectionCreated( _
        ByVal sender As Object, _
        ByVal e As PlcNotifications.PlcDeviceConnectionEventArgs)
    Dim connection = e.Connection
 
    If ... Then
        ' ...
    End If
End Sub

Access Status

The following types are used: PlcDeviceConnection, PlcNotifications and PlcStatus.

Access to a certain data area can fail for several reasons. While an area either no longer exists, the start address may also be valid, but the end of data no longer corresponds to the expected end. Other situations like that are valid data, since no initial value may have been set. The cause of problems when accessing the data areas can be quickly found out using appropriate status codes.

If PlcValue instances are used for access, the status can be checked for each PLC variable.

Dim speedVariable = New PlcInt32("DB1.DBD 1")
connection.ReadValue(speedVariable)
 
If speedVariable.Status.Code = PlcStatusCode.NoError Then
    ' ...
End If

In addition, the status can be checked down to the level of the PLC data type. Therefor the GetStatus-method is used. There is also the possibility to take the evaluation of an operation into your own hands. This makes it possible to evaluate a failed operation, which can also lead to an exception, yourself and to declare it as “OK”. This is useful, for example, when developing a standard application for the controls of a system, but these do not have the same data areas, which is why a non-addressable data area can also be ignored.

For user-defined evaluation, a user-defined method must be entered in the static PlcNotifications class.

PlcNotifications.EvaluateStatus = AddressOf EvaluateStatus
 
...
 
Private Shared Function EvaluateStatus(ByVal provider As IPlcStatusProvider) As Boolean
    Dim connection As PlcDeviceConnection = TryCast(provider, PlcDeviceConnection)
    Dim value As IPlcValue = TryCast(provider, IPlcValue)
 
    If connection IsNot Nothing Then
        ' ...
    ElseIf value IsNot Nothing Then
        ' ...
    End If
 
    Return True
End Function

The following types are used: SimaticDevice, IPlcDeviceInfo, PlcBlockInfo and PlcOperand.

Occasionally the device information of the controller is crucial to find out whether you are working with the right controller and where it is exactly. An instance of the IPlcDeviceInfo interface can be called up using the GetInfo method of the PlcDevice class to call up the device data availabe for this. The instance then contains all the device data provided.

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

It should be noted that not every controller provides all of the device information shown here. To check whether information is available, one of the has-properties can be used.

General

The following types are used: PlcDevice and PlcDeviceConnection.

The class PlcDevice and PlcDeviceConnection are used as base classes of SimaticDevice and SimaticDeviceConnection. As a result, the SimaticDevice class inherits, for example, the EndPoint property for configuring the endpoint via which the controller is to be connected. The PlcDeviceConnection also provides various properties. Part of there are properties for controlling the timeout behavior and termination detection.

Further specific settings depend on the provider used (= PlcDevice derivative) and can be configured accordingly after a cast to the PlcDeviceConnections specific types.

Device Types

The following types are used: SimaticDevice, SimaticDeviceType and SimaticChannelType.

The framework generally tries to automatically determine the device types and the appropriate channels type for the controller. Depending on the type of control used and the structure of the network, it may be necessary to define the device types or the channel type manually.

Dim device = New SimaticDevice("192.168.0.80")
device.Type = SimaticDeviceType.S71200
device.ChannelType = SiemensChannelType.ProgrammerDevice

Endpoints

The following types are used: SimaticDevice, IPDeviceEndPoint and SimaticDeviceType.

Generally, either the DNS-name or the IP address of the controller is sufficient for access. Depending on the type of control and setup of the network, the rack and slot number of the control may also have to be specified.

Dim device = New SimaticDevice()
device.Type = SimaticDeviceType.S71500
device.ChannelType = SiemensChannelType.OperationPanel
device.EndPoint = New IPDeviceEndPoint("192.168.0.80", rack:=0, slot:=2)

Licensing

The IP S7 LINK SDK comes with an evaluation license which can be used unlimited for each application run for 30 minutes. If this restriction limits your evaluation options, you can request another evaluation license from us.

Just ask our support (via support@traeger.de) or let us consult you directly and clarify open questions with our developers!

After receiving your personalized license key for IP S7 LINK development it has to be committed to the framework. Hereto insert the following code line into your application before accessing the SimaticDeviceConnection class for the first time. Replace <insert your license code here> with the license key you received from us.

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

Additionally you receive information about the license currently used by the framework via the LicenseInfo property of the IPS7Lnk.Advanced.Licenser class. This works as follows:

Dim license As ILicenseInfo = IPS7LnkNet.Advanced.Licenser.LicenseInfo
 
If license.IsExpired Then _
    Console.WriteLine("The IP S7 LINK SDK license is expired!")

In the course of development/evaluation, it is mostly irrelevant whether the test license or the license already purchased is being used. However, as soon as the application goes into productive use, it is annoying if the application stops working during execution due to an invalid license. For this reason, we recommend implementing the following code snippet in the application and at least executing it when the application is started:

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

You can receive further information about licensing, purchase or other questions directly on our product page at: www.traeger.de.