Client - User defined timestamp clock source
In some applications, a time stamp that originates from an external source (e.g. a GPS clock) should also be used in addition to the setpoint, for example. This example shows the implementation of a user-defined clock/time for timestamping tasks.
Download TwinCAT XAE Project (*.zip): Sample15.zip
The example described here uses the state machine that is described in the "General Client project structure" chapter. The States 0, 1, 11 and 100 are identical to the state machine described there. Other states were modified for the example or new states were also added.
The TwinCAT IEC 61850 Client implementation uses the interface: "I_ScsmSystemClockEventSink" to query the time for time stamping tasks. It is possible to use a custom function block that implements this special interface and configures the client function block to use the new time source. In the Global Variable List "TcTelecontrol", the new time source is assigned to the client function block by setting the property "ipSystemClock:=fbMyClock". The client function block will then call the method: "OnGetSystemTime" each time it needs a new time stamp from it. The IEC 61850 client-server communication uses time stamps in at least two different formats: UTC time and binary time. For this reason, this method returns the time stamp as output variables in these two formats.
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
The sample demonstrates a very simple software clock, which was implemented with the help of the RTC_EX function block.
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);