Client - User defined timestamp clock source

In einigen Applikationen soll z.B. neben dem Sollwert auch ein Zeitstempel verwendet werden, der von einer externen Quelle stammt (z.B. einer GPS-Uhr). Dieses Beispiel zeigt die Implementierung einer Benutzerdefinierten Uhr/Uhrzeit für Zeitstempelungsaufgaben.

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

Das hier beschriebene Beispiel nutzt die Statemachine, welche in dem Kapitel „Allgemeine Client - Projektstruktur“ beschrieben ist. Die States: 0,1,11 und 100 sind identisch zu der dort beschriebenen Statemachine. Andere States wurden für das Beispiel modifiziert oder auch neue States hinzugefügt.

Die TwinCAT IEC 61850 Client-Implementierung verwendet die Schnittstelle: „I_ScsmSystemClockEventSink“, um die Uhrzeit für Zeitstempelungsaufgaben abzufragen. Es ist möglich einen eigenen Funktionsbaustein zu verwenden, der diese spezielle Schnittstelle implementiert und den Client-Baustein so konfiguriert, dass dieser die neue Zeitquelle verwendet. In der globalen Variablenliste „TcTelecontrol“ wird dem Client-Baustein durch das Setzen der Eigenschaft „ipSystemClock:=fbMyClock“ die neue Zeitquelle zugewiesen. Der Client-Baustein wird danach jedes Mal die Methode: „OnGetSystemTime“ aufrufen, wenn von ihm ein neuer Zeitstempel benötigt wird. Die IEC 61850 Client-Server-Kommunikation verwendet Zeitstempel in mindestens zwei verschiedenen Formaten: UTC-Time und Binary-Time. Aus diesem Grund liefert diese Methode den Zeitstempel als Ausgangsvariablen in diesen zwei Formaten.

VAR_GLOBAL
    ipCreator   : I_AcsiCodeCreatorClass := GVL_AcsiVars.Creator.SetCodeRev(codeRev:=2).SetGuiVer(major:=1, minor:=0, build:=93, revision:=10);
    fbIED       : FB_IED_IED;
    (* User defined clock (time stamp source) *)
    fbMyClock   : FB_MyClock;
    fbIEDClient : FB_IEDClient := (fbConnection:=(ipIED:=fbIED, ipSystemClock:=fbMyClock, settings:=(sRemoteHost:='127.0.0.1')));
END_VAR

Das Beispiel demonstriert eine sehr einfache Software-Uhr, die mit Hilfe des RTC_EX-Funktionsbausteins realisiert wurde.

FUNCTION_BLOCK FB_MyClock IMPLEMENTS I_ScsmSystemClockEventSink
VAR
    _tT : T_UtcTime:=(secondSinceEpoch:=DT#2021-04-01-00:00:00, quality:=(ClockNotSynchronized:=TRUE, ClockFailure:=FALSE, LeapSecondsKnown:=FALSE), fractionOfSecond:=[0,0,0]);(* Actual UTC time. *)
    _tB : T_BinaryTime;(* Actual binary-time (EntryTime) *)
    clock : RTC_EX:=(EN:=TRUE, PDT:=DT#2021-04-01-00:00:00, PMSEK:=0);
    refreshTimer : TON:=(IN:=TRUE, PT:=T#1S);
END_VAR
METHOD FINAL Execute : BOOL
VAR_INPUT
END_VAR
refreshTimer();
IF Execute:=refreshTimer.Q THEN
    refreshTimer(IN:=FALSE); refreshTimer(IN:=TRUE);
    Update();
END_IF
METHOD FINAL OnGetSystemTime : BOOL
VAR_INPUT
    ipAA: I_ScsmAssociationClass;(* Application association. If = 0 => optional or unknown. *)
END_VAR
VAR_OUTPUT
    tT: T_UtcTime;(* UTC-time. *)
    tB: T_BinaryTime;(* Binary-time *)
END_VAR
tT:=_tT;
tB:=_tB;
OnGetSystemTime:=TRUE;
METHOD FINAL SetClock
VAR_INPUT
    tSet : DT;(* New time to set *)
END_VAR
clock(EN:=FALSE);
clock(EN:=TRUE, PDT:=tSet);
_tT.quality.ClockNotSynchronized:=FALSE;
Update();
METHOD FINAL Update
VAR_INPUT
END_VAR
clock();(* update clock time *)

(* convert to utc-time format *)
_tT.secondSinceEpoch:=clock.CDT;
_tT.fractionOfSecond:=LTIME_TO_UtcTimeFractionofSecond(in:=TIME_TO_LTIME(DWORD_TO_TIME(clock.CMSEK)));
Accuracy_To_UtcTimeQualityAccuracy(in:=E_UtcTimeAccuracy._03, bAccuracy0=>_tT.quality.Accuracy0, bAccuracy1=>_tT.quality.Accuracy1, bAccuracy2=>_tT.quality.Accuracy2, bAccuracy3=>_tT.quality.Accuracy3, bAccuracy4=>_tT.quality.Accuracy4);

(* convert to binary-time format *)
_tB.day:=Date_To_BinaryTime6Day(in:=DT_TO_DATE(clock.CDT));
_tB.timeOfDay:=DT_TO_TOD(clock.CDT) + DWORD_TO_TIME(clock.CMSEK);