General Server - Project structure

All sample Server projects also follow a general structure, similar to the sample Client projects. In contrast to the client, the connection at the server is not actively established on the server side. After the program start, the server waits for a connection request from a client and accepts or rejects it. In addition, it must be possible for the server to establish connections to multiple clients.

This results in a different server project structure than for the client. The basic structure of the TwinCAT IEC 61850 Server sample projects is based on the PLC project structure automatically generated by the TwinCAT Telecontrol Configurator. The TwinCAT Telecontrol Configurator in turn uses the "TwinCAT XAE Project (XML format)" as a template when generating the solution. The data models communicated in the samples reflect different IEC 61850 servers. They differ from sample to sample and are enclosed with the source code as ICD files. The ICD files can also be used by third-party software for simulation purposes.

Structure of a TwinCAT IEC 61850 PLC Server project:

General Server - Project structure 1:

The generated solution name (unless specified otherwise) corresponds to the TwinCAT Telecontrol Configurator project name. The automatically generated TwinCAT PLC project name (unless specified otherwise) on the other hand has the following structure: "[Project name]_[IEDName]_Server".

As standard, every sample project has a "DUTs", a "GVLs" and a "POUs" folder. A Global Variable List (GVL) with the name "TcTelecontrol" is stored in the "GVLs" folder. The following function blocks are instantiated and initialized in this Global Variable List (see source code below):

In addition, the code version used during code generation and the version of the TwinCAT Telecontrol Configurator used are also stored there.

Namespace: TcTelecontrol

Type: Global Variable List (GVL)

VAR_GLOBAL
    ipCreator                 : I_AcsiCodeCreatorClass := GVL_AcsiVars.Creator.SetCodeRev(codeRev:=2).SetGuiVer(major:=1, minor:=1, build:=94, revision:=1);
    fb[IEDName]               : FB_IED_[IEDName];
    fb[IEDName]Server         : FB_iec61850ServerClass := (ipIED:=fb[IEDName], settings:=(bEnable:=TRUE, sLocalHost:='127.0.0.1'));
    fb[IEDName]ServerSession1 : FB_[IEDName]ServerSession := (fbConnection:=(ipServer:=fb[IEDName]Server, settings:=(bEnable:=TRUE)));
    fb[IEDName]Gse            : FB_[IEDName]Gse := (fbAdapter:=(ipIED:=fb[IEDName], settings:=(sMulticastAddr:='01-0C-CD-01-00-00', eDispatchMode:=E_GseDispatchMode.NonPromiscuous)));
END_VAR

In the "POUs" folder there is a further folder: "[IEDName]", which contains the entire hierarchical structure of the IED data model as function blocks. This folder also contains the IED data model function block that is instantiated in the Global Variable List and that has already been mentioned. The server session function block: "FB_[IEDName]ServerSession", which implements the establishment of the connection and the data exchange with an IEC 61850 Client, is located on the same level.

The TwinCAT PLC project contains a "MAIN" program as standard. This is called cyclically by a TwinCAT task and in turn calls the program "P_IEC61850MAIN". The program "P_IEC61850MAIN" encapsulates the call of the server, server session and the optional Gse function block, separates the IEC 61850 communication from the rest of the PLC machine program.

PROGRAM MAIN
VAR
END_VAR
P_IEC61850MAIN();
PROGRAM P_IEC61850MAIN
VAR
END_VAR
fb[IEDName]Server.Execute();
fb[IEDName]ServerSession1();
fb[IEDName]Gse();

In the FB_[IEDName]ServerSession function block, there is a state machine, the basic states of which are used in every server sample (see source code below). The server session function block is responsible for establishing connections and exchanging data with a single client. If there are multiple simultaneous client connections, multiple instances of this function block are required and instantiated.

State 0 (Init state): the state machine is in this state as soon as the PLC program has been started. Commands for the management of a client-server connection are handled here (and in State 1). Normally, the server session function block remains in this state and waits for a connection request from a client. The server then establishes a connection as soon as the connection request is detected. This happens automatically and does not require any further commands from the PLC application. If the server has established a connection to the client, the state machine switches to the data transmission state (State 10).

It is also possible to close an already established connection. This is controlled via two Boolean variables. When set, these variables enable the corresponding commands (in this case these are once-only method calls on the server session function block).

The methods listed above require longer than one PLC cycle for their execution. For this reason the state machine switches to a wait state (State 1), in which the termination of the activated command is awaited.

State 1 (Wait State): in this state, the server session function block waits until the command processing for the management of the server client connection is no longer busy. As long as the connection is being released or interrupted, the state machine is in State 1. The state machine is reset to State 0 (Init State) as soon as the command has been successfully executed.

State 10 (Data exchange): if the state machine is in this state, then the server connection to the client has already been successfully established. The server session function block is ready for data transmission to the server. The server data transmission to the client takes place automatically in the background and does not have to be initiated by the PLC application. It is the client that triggers a data transmission in the server by a request.

The state machine switches between states 0 and 10 when there is an active connection. The state machine is reset to State 0 in order to react to changes in the client-server connection status and to handle them in State 0.

State 100 (Error state): as soon as an error occurs during the activation or processing of a command, the state machine is set to State 100. The error is logged here and the state machine reset to State 0.

FUNCTION_BLOCK FB_[IEDName]ServerSession
VAR_INPUT
    fbConnection     : FB_iec61850ConnectionClass := (ipAbortInd:=THIS^, ipAssociateInd:=THIS^, ipReleaseInd:=THIS^);
END_VAR
VAR
    _bAbort          : BOOL;
    _bDisconnect     : BOOL;
    state            : BYTE;
    eState           : E_AsyncEnvironmentState;
    bBusy            : BOOL;
    bSuccess         : BOOL;
    ipResult         : I_AsyncServiceResultClass;
    sLastErrorResult : T_MaxString;
    fbAbortReason    : FB_ServiceErrorClass := (stError:=SUCCESS_EVENT);
    sLastAbortReason : T_MaxString;
END_VAR
fbConnection.Execute();
eState:= fbConnection.eState;

CASE state OF
    0:
        IF _bAbort THEN
            _bAbort:= FALSE;
            bSuccess:= fbConnection.AbortReq(ipReason:=fbAbortReason, ipSink:=0, ipResult=>ipResult);
            state:= SEL(bSuccess, 100, 1);
        ELSIF eState = E_AsyncEnvironmentState.Established AND _bDisconnect THEN
            _bDisconnect:= FALSE;
            bSuccess:= fbConnection.ReleaseReq(ipSink:=0, ipResult=>ipResult);
            state:= SEL(bSuccess, 100, 1);
        ELSIF eState = E_AsyncEnvironmentState.Established THEN
            state:= 10;
        END_IF
        _bDisconnect:= FALSE;
    1:
        IF ipResult <> 0 THEN
            ipResult.Execute();
            IF NOT (bBusy:=ipResult.IsBusy()) THEN
                state:= SEL(ipResult.IsCompleted(), 100, 0);
            END_IF
        END_IF
    10:
        state:= 0;
    100:
        state:= 0;
        IF ipResult <> 0 THEN
            sLastErrorResult:= ipResult.Dump();
        END_IF
END_CASE

GOOSE Publisher (optional)

TwinCAT Telecontrol Configurator can also generate the PLC code for a GOOSE publisher in a server project during PLC code generation (see code sample below). However, this is only possible if the user has previously created the GOOSE components such as GoCBs (goose control blocks) in the TwinCAT Telecontrol Configurator or imported them from an SCL file (e.g. ICD file). By default, a function block with the name: "FB_[IEDName]Gse" is instantiated during code generation and added to the Global Variable List "TcTelecontrol". This function block establishes the connection between a network adapter of the TwinCAT control computer, the IED data model and the GOOSE configuration in the GoCBs. The GoCBs are instantiated in the IED data model (usually in LLN0). Each GoCB has a function block subelement with the name: "Publisher". The "Publisher" method calls can be used to start or stop publishing from the PLC code. By default, publishing is started at PLC program start for all GoCBs. This is controlled by the "bStart" variable initialized with "TRUE". Publishing can be stopped for all GoCBs via a rising edge at the "bStop" variable. Publisher commands issued through these methods are executed immediately, without wait cycles or further states required to complete command processing. The "Publisher" described here reads the configuration and does update the status of the GoCB (attribute "GoEna" is set to "TRUE" or "FALSE", for example), but it does not use the client-server services such as "SetGoCBValues" or "GetGoCBValues" to start or stop the Publisher. This means that the generated code already implements a publisher that can be started or stopped, for example, in the first PLC cycle or from the PLC code at any time. The required GoCB configuration settings (GoCB attribute values) can be made via initialization values. However, the GoCBs can already be configured in the TwinCAT Telecontrol Configurator. The initialization values are then automatically generated and assigned during code generation. If the Publisher has been started and the configuration of the GoCB and the network adapter shows a match, then the Publisher immediately starts sending the first GOOSE frames (including frame repetitions). The "Update" method has a special significance. Every time it is called, the "Publisher" immediately sends a new GOOSE frame (and automatically new frame repetitions). This means that the application can set all relevant GOOSE dataset data in the IED data model first and then initiate the sending of the changed dataset data with the "Update" method call. The "Execute" method must be called cyclically the rest of the time. It is responsible for sending the frame repetitions and updating the status information in the GoCB.

FUNCTION_BLOCK FB_[IEDName]Gse IMPLEMENTS I_GseLinkStatusEventSink
VAR_INPUT
    fbAdapter   : FB_GseAdapterClass := (ipLinkStatus:=THIS^);
END_VAR
VAR
    eLinkStatus : E_GseLinkStatus;
    bSuccess    : BOOL;
    ipError     : I_ServiceErrorClass;
    bStart      : BOOL := TRUE;
    bStop       : BOOL;
    bUpdate     : BOOL;
END_VAR
bSuccess:= fbAdapter.Execute(ipError=>ipError);

IF bStart THEN
    bStart:= FALSE;
    bSuccess:= fb[IEDName].IEDLD1.LLN0.gocb01.Publisher.Start(ipAdapter:=fbAdapter, ipError=>ipError);
    bSuccess:= fb[IEDName].IEDLD1.LLN0.gocb02.Publisher.Start(ipAdapter:=fbAdapter, ipError=>ipError);
    bSuccess:= fb[IEDName].IEDLD1.LLN0.gocb03.Publisher.Start(ipAdapter:=fbAdapter, ipError=>ipError);
ELSIF bStop THEN
    bStop:= FALSE;
    bSuccess:= fb[IEDName].IEDLD1.LLN0.gocb01.Publisher.Stop(ipError=>ipError);
    bSuccess:= fb[IEDName].IEDLD1.LLN0.gocb02.Publisher.Stop(ipError=>ipError);
    bSuccess:= fb[IEDName].IEDLD1.LLN0.gocb03.Publisher.Stop(ipError=>ipError);
ELSIF bUpdate THEN
    bUpdate:= FALSE;
    bSuccess:= fb[IEDName].IEDLD1.LLN0.gocb01.Publisher.Update(ipError=>ipError);
    bSuccess:= fb[IEDName].IEDLD1.LLN0.gocb02.Publisher.Update(ipError=>ipError);
    bSuccess:= fb[IEDName].IEDLD1.LLN0.gocb03.Publisher.Update(ipError=>ipError);
ELSE
    bSuccess:= fb[IEDName].IEDLD1.LLN0.gocb01.Publisher.Execute(ipError=>ipError);
    bSuccess:= fb[IEDName].IEDLD1.LLN0.gocb02.Publisher.Execute(ipError=>ipError);
    bSuccess:= fb[IEDName].IEDLD1.LLN0.gocb03.Publisher.Execute(ipError=>ipError);
END_IF

The GSE block implements the "I_GseLinkStatusEventSink" interface. The method: "OnLinkStatusChange" belongs to this interface implementation and is called whenever the status of the network connection (at the network adapter) changes. The PLC application can, for example, query or check the network connection status via "eLinkStatus" variable.

METHOD OnLinkStatusChange
VAR_INPUT
    ipAdapter : I_GseAdapterClass;
    eStatus   : E_GseLinkStatus;
END_VAR
VAR
END_VAR
eLinkStatus:= eStatus;

In the project tree under the I/O-Device branch you will find a network adapter instance named "GSE (RT Ethernet adapter)". This adapter instance must be configured accordingly, i.e. the I/O configuration must be adapted to the existing hardware and to the target platform on which the project is to run.
A new I/O configuration is also necessary if you change the target platform. This configuration must be done manually in TwinCAT XAE. In addition to the I/O configuration of the network adapter, a link must be established between the network adapter and the PLC function blocks for Goose communication. The link can be used to forward the data received from the network adapter to the instance of the function block: "FB_[IEDName]Gse". In the opposite direction the instance of the function block "FB_[IEDName]Gse" can forward the data to be sent to the network adapter.

Here you can find more information: RT Ethernet adapter Configuration.