Server - GOOSE Publisher (without Client-Server communication)

In a Server project, the TwinCAT Telecontrol Configurator also generates a Server block and one or more instances of the Server session block by default (see: "General Server project structure"). The Server and ServerSession block can, for example, ensure that the Publisher can be activated/deactivated from the Client via Client-Server services such as "GetGoCBDataValues" or "SetGoCBDataValues" or that the GoCBs can be configured. In some cases, however, Client-Server communication with the device should be omitted and only a "pure" GOOSE Publisher should be implemented. Such a Publisher can automatically start sending GOOSE messages after the PLC program start. This example shows the implementation of a Publisher, but without the Client-Server communication part. The parts of the Server project that are not needed have been deliberately removed in this example.

Download TwinCAT XAE Project (*.zip): Sample12.zip

Namespace: TcTelecontrol

Type: Global Variable List (GVL)

In the Global Variable List, an IED data model function block instance ("fbIED") and one or more GSE function block instances for GOOSE communication and GSE management ("fbIEDGse") are required. This sample uses only one network adapter for GOOSE communication and three GoCBs in the IED data model.

VAR_GLOBAL
    ipCreator : I_AcsiCodeCreatorClass := GVL_AcsiVars.Creator.SetCodeRev(codeRev:=2).SetGuiVer(major:=1, minor:=0, build:=93, revision:=10);
    fbIED     : FB_IED_IED;
    fbIEDGse  : FB_IEDGse := (fbAdapter:=(ipIED:=fbIED, settings:=(sMulticastAddr:='01-0C-CD-01-00-01', eDispatchMode:=E_GseDispatchMode.NonPromiscuous)));
END_VAR

The "MAIN" program is called cyclically by a TwinCAT task and only needs to call the "P_IEC61850MAIN" program. "P_IEC61850MAIN" in turn calls the GSE function block responsible for sending the GOOSE messages and mapping the received data from the IED data model in the GOOSE messages.

PROGRAM MAIN
VAR
END_VAR
P_IEC61850MAIN();
PROGRAM P_IEC61850MAIN
VAR
END_VAR
fbIEDGse();

In the sample implementation of the GSE function block, the Publishing process is automatically started for all three GoCBs after PLC startup. A rising edge at the "bStop" variable stops the Publishing process of the GoCBs. The value changes of some GOOSE data are simulated in the sample. Every 5 s, some values of the GoCB DataSet members are modified and a rising edge is generated at the variable "bUpdate". This rising edge causes the Publishers to generate and send a new GOOSE message. The PLC application does not have to take care of the GOOSE message repetitions. This is done automatically.

FUNCTION_BLOCK FB_IEDGse IMPLEMENTS I_GseSystemClockEventSink, I_GseLinkStatusEventSink
VAR_INPUT
    fbAdapter     : FB_GseAdapterClass := (ipSystemClock:=THIS^, ipLinkStatus:=THIS^);
END_VAR
VAR
    eLinkStatus   : E_GseLinkStatus;
    bSuccess      : BOOL;
    ipError       : I_ServiceErrorClass;
    bStart        : BOOL := TRUE;
    bStop         : BOOL;
    bUpdate       : BOOL;

    bSimulation   : BOOL := TRUE;
    tSimulation   : TIME := T#5S;
    fbUpdateTimer : TON;

    bSync         : BOOL := TRUE;
    tSync         : T_UtcTime := String_TO_UtcTime(in:='UT#2019-07-12-12:00:00.000000000|000|3');
    fbClock       : FB_GseSystemClock;
END_VAR
fbUpdateTimer(IN:=bSimulation, PT:=tSimulation);
IF fbUpdateTimer.Q THEN
    fbUpdateTimer(IN:=FALSE);
    fbUpdateTimer(IN:=bSimulation);
    
    fbIED.IEDLD1.LEDGGIO1.SPCSO1.stVal.bValue:= NOT fbIED.IEDLD1.LEDGGIO1.SPCSO1.stVal.bValue;
    fbIED.IEDLD1.LEDGGIO2.SPCSO1.stVal.bValue:= NOT fbIED.IEDLD1.LEDGGIO2.SPCSO1.stVal.bValue;
    fbIED.IEDLD1.LEDGGIO3.SPCSO1.stVal.bValue:= NOT fbIED.IEDLD1.LEDGGIO3.SPCSO1.stVal.bValue;
    fbIED.IEDLD1.LEDGGIO4.SPCSO1.stVal.bValue:= NOT fbIED.IEDLD1.LEDGGIO4.SPCSO1.stVal.bValue;
    fbIED.IEDLD1.LEDGGIO5.SPCSO1.stVal.bValue:= NOT fbIED.IEDLD1.LEDGGIO5.SPCSO1.stVal.bValue;
    fbIED.IEDLD1.LEDGGIO6.SPCSO1.stVal.bValue:= NOT fbIED.IEDLD1.LEDGGIO6.SPCSO1.stVal.bValue;
    fbIED.IEDLD1.LEDGGIO7.SPCSO1.stVal.bValue:= NOT fbIED.IEDLD1.LEDGGIO7.SPCSO1.stVal.bValue;
    fbIED.IEDLD1.LEDGGIO8.SPCSO1.stVal.bValue:= NOT fbIED.IEDLD1.LEDGGIO8.SPCSO1.stVal.bValue;

    fbIED.IEDLD1.MMXU1.TotW.mag.f.fValue:= fbIED.IEDLD1.MMXU1.TotW.mag.f.fValue + 0.1;
    
    IF fbIED.IEDLD1.XCBR1.Pos.stVal.eValue = E_AcsiDbpos.On THEN 
        fbIED.IEDLD1.XCBR1.Pos.stVal.eValue:= E_AcsiDbpos.Off;
    ELSE
        fbIED.IEDLD1.XCBR1.Pos.stVal.eValue:= E_AcsiDbpos.On;
    END_IF
    fbIED.IEDLD1.XCBR1.Pos.q.OldData:= NOT fbIED.IEDLD1.XCBR1.Pos.q.OldData;
    fbIED.IEDLD1.XCBR1.Pos.t.SecondSinceEpoch:= fbIED.IEDLD1.XCBR1.Pos.t.SecondSinceEpoch + TIME#1S;

    bUpdate:= TRUE;
END_IF
IF bSync THEN
    bSync:= FALSE;
    bSuccess:= fbClock.SetToUtcTime(in:=tSync);
ELSE
    fbClock.Execute();
END_IF
bSuccess:= fbAdapter.Execute(ipError=>ipError);

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

The GSE function block implements the "I_GseSystemClockEventSink" interface. The method: "OnGetSystemTime" belongs to this interface implementation and is called whenever a Publisher needs a new time stamp for a GOOSE message. For example, the PLC application could transfer its own time stamp, perhaps from a GPS clock, to the GOOSE message. In the sample, a simple software demo clock is used for time stamping.

METHOD OnGetSystemTime : BOOL
VAR_INPUT
    ipAdapter : I_GseAdapterClass;
END_VAR
VAR_OUTPUT
    tT        : T_UtcTime;
END_VAR
VAR
END_VAR
OnGetSystemTime:= fbClock.OnGetSystemTime(ipAdapter:=ipAdapter, tT=>tT);

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.